隊(duì)列的概念在 順序隊(duì)列 中,而使用循環(huán)隊(duì)列的目的主要是規(guī)避假溢出造成的空間浪費(fèi),在使用循環(huán)隊(duì)列處理假溢出時(shí),主要有三種解決方案

公司主營(yíng)業(yè)務(wù):網(wǎng)站制作、網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶(hù)真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)建站是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶(hù)帶來(lái)驚喜。創(chuàng)新互聯(lián)建站推出麥蓋提免費(fèi)做網(wǎng)站回饋大家。
本文提供后兩種解決方案。
順序隊(duì)和循環(huán)隊(duì)列是一種特殊的線性表,與順序棧類(lèi)似,都是使用一組地址連續(xù)的存儲(chǔ)單元依次存放自隊(duì)頭到隊(duì)尾的數(shù)據(jù)元素,同時(shí)附設(shè)隊(duì)頭(front)和隊(duì)尾(rear)兩個(gè)指針,但我們要明白一點(diǎn),這個(gè)指針并不是指針變量,而是用來(lái)表示數(shù)組當(dāng)中元素下標(biāo)的位置。
本文使用切片來(lái)完成的循環(huán)隊(duì)列,由于一開(kāi)始使用三個(gè)參數(shù)的make關(guān)鍵字創(chuàng)建切片,在輸出的結(jié)果中不包含nil值(看起來(lái)很舒服),而且在驗(yàn)證的過(guò)程中發(fā)現(xiàn)使用append()函數(shù)時(shí)切片內(nèi)置的cap會(huì)發(fā)生變化,在消除了種種障礙后得到了一個(gè)四不像的循環(huán)隊(duì)列,即設(shè)置的指針是順序隊(duì)列的指針,但實(shí)際上進(jìn)行的操作是順序隊(duì)列的操作。最后是對(duì)make()函數(shù)和append()函數(shù)的一些使用體驗(yàn)和小結(jié),隊(duì)列的應(yīng)用放在鏈隊(duì)好了。
官方描述(片段)
即切片是一個(gè)抽象層,底層是對(duì)數(shù)組的引用。
當(dāng)我們使用
構(gòu)建出來(lái)的切片的每個(gè)位置的值都被賦為interface類(lèi)型的初始值nil,但是nil值也是有大小的。
而使用
來(lái)進(jìn)行初始化時(shí),雖然生成的切片中不包含nil值,但是無(wú)法通過(guò)設(shè)置的指針變量來(lái)完成入隊(duì)和出隊(duì)的操作,只能使用append()函數(shù)來(lái)進(jìn)行操作
在go語(yǔ)言中,切片是一片連續(xù)的內(nèi)存空間加上長(zhǎng)度與容量的標(biāo)識(shí),比數(shù)組更為常用。使用 append 關(guān)鍵字向切片中追加元素也是常見(jiàn)的切片操作
正是基于此,在使用go語(yǔ)言完成循環(huán)隊(duì)列時(shí),首先想到的就是使用make(type, len, cap)關(guān)鍵字方式完成切片初始化,然后使用append()函數(shù)來(lái)操作該切片,但這一方式出現(xiàn)了很多問(wèn)題。在使用append()函數(shù)時(shí),切片的cap可能會(huì)發(fā)生變化,用不好就會(huì)發(fā)生擴(kuò)容或收縮。最終造成的結(jié)果是一個(gè)四不像的結(jié)果,入隊(duì)和出隊(duì)操作變得與指針變量無(wú)關(guān),失去了作為循環(huán)隊(duì)列的意義,用在順序隊(duì)列還算合適。
參考博客:
Go語(yǔ)言中的Nil
Golang之nil
Go 語(yǔ)言設(shè)計(jì)與實(shí)現(xiàn)
數(shù)組
數(shù)組是內(nèi)置(build-in)類(lèi)型,是一組同類(lèi)型數(shù)據(jù)的集合。
數(shù)組的初始化有多種形式
長(zhǎng)度為5的數(shù)組,其元素值依次為:1,2,3,4,5
長(zhǎng)度為5的數(shù)組,其元素值依次為:1,2,0,0,0 。在初始化時(shí)沒(méi)有指定初值的元素將會(huì)賦值為其元素類(lèi)型int的默認(rèn)值0,string的默認(rèn)值是 ""
長(zhǎng)度為5的數(shù)組,其長(zhǎng)度是根據(jù)初始化時(shí)指定的元素個(gè)數(shù)決定的
長(zhǎng)度為5的數(shù)組,key:value,其元素值依次為:0,0,1,2,3。在初始化時(shí)指定了2,3,4索引中對(duì)應(yīng)的值:1,2,3
長(zhǎng)度為5的數(shù)組,起元素值依次為:0,0,1,0,3。由于指定了最大索引4對(duì)應(yīng)的值3,根據(jù)初始化的元素個(gè)數(shù)確定其長(zhǎng)度為5
切片
數(shù)組的長(zhǎng)度不可改變,在特定場(chǎng)景中這樣的集合就不太適用,Go中提供了一種靈活,功能強(qiáng)悍的內(nèi)置類(lèi)型 Slices 切片。
切片可以通過(guò)數(shù)組來(lái)初始化,也可以通過(guò)內(nèi)置函數(shù)make()初始化。初始化時(shí)len=cap,在追加元素時(shí)如果容量cap不足時(shí)將按len的 2 倍擴(kuò)容。
直接初始化切片, [] 表示是切片類(lèi)型, {1,2,3} 初始化值依次是1,2,3.其cap=len=3
初始化切片s,是數(shù)組arr的引用
將arr中從下標(biāo)startIndex到endIndex-1 下的元素 創(chuàng)建為一個(gè)新的切片
缺省endIndex時(shí)將表示一直到arr的最后一個(gè)元素
缺省startIndex時(shí)將表示從arr的第一個(gè)元素開(kāi)始
通過(guò)切片s初始化切片s1
通過(guò)內(nèi)置函數(shù)make()初始化切片s,[]int 標(biāo)識(shí)為其元素類(lèi)型為int的切片
定義一個(gè)切片,然后讓切片去引用一個(gè)已經(jīng)創(chuàng)建好的數(shù)組。基本語(yǔ)法如下:
索引1:切片引用的起始元素位
索引2:切片只引用該元素位之前的元素
例程如下:
在該方法中,我們未指定容量cap,這里的值為5是系統(tǒng)定義的。
在方法一中,可以用arr數(shù)組名來(lái)操控?cái)?shù)組中的元素,也可以通過(guò)slice切片來(lái)操控?cái)?shù)組中的元素。切片是直接引用數(shù)組,數(shù)組是事先存在的,程序員是可見(jiàn)的。
通過(guò) make 來(lái)創(chuàng)建切片,基本語(yǔ)法如下:
make函數(shù)第三個(gè)參數(shù)cap即容量是可選的,如果一定要自己注明的話,要注意保證cap≥len。
用該方法可以 指定切片的大小(len)和容量(cap)
例程如下:
由于未賦值系統(tǒng)默認(rèn)將元素值置為0,即:
數(shù)值類(lèi)型數(shù)組:????默認(rèn)值為 0
字符串?dāng)?shù)組:? ? ? ?默認(rèn)值為 ""
bool數(shù)組:? ? ? ? ? ?默認(rèn)值為 false
在方法二中,通過(guò)make方式創(chuàng)建的切片對(duì)應(yīng)的數(shù)組是由make底層維護(hù),對(duì)外不可見(jiàn),即只能通過(guò)slice去訪問(wèn)各個(gè)元素。
定義一個(gè)切片,直接就指定具體數(shù)組,使用原理類(lèi)似于make的方式。
例程如下:
Go 中的分片數(shù)組,實(shí)際上有點(diǎn)類(lèi)似于Java中的ArrayList,是一個(gè)可以擴(kuò)展的數(shù)組,但是Go中的切片由比較靈活,它和數(shù)組很像,也是基于數(shù)組,所以在了解Go切片前我們先了解下數(shù)組。
數(shù)組簡(jiǎn)單描述就由相同類(lèi)型元素組成的數(shù)據(jù)結(jié)構(gòu), 在創(chuàng)建初期就確定了長(zhǎng)度,是不可變的。
但是Go的數(shù)組類(lèi)型又和C與Java的數(shù)組類(lèi)型不一樣, NewArray 用于創(chuàng)建一個(gè)數(shù)組,從源碼中可以看出最后返回的是 Array{}的指針,并不是第一個(gè)元素的指針,在Go中數(shù)組屬于值類(lèi)型,在進(jìn)行傳遞時(shí),采取的是值傳遞,通過(guò)拷貝整個(gè)數(shù)組。Go語(yǔ)言的數(shù)組是一種有序的struct。
Go 語(yǔ)言的數(shù)組有兩種不同的創(chuàng)建方式,一種是顯示的初始化,一種是隱式的初始化。
注意一定是使用 [...]T 進(jìn)行創(chuàng)建,使用三個(gè)點(diǎn)的隱式創(chuàng)建,編譯器會(huì)對(duì)數(shù)組的大小進(jìn)行推導(dǎo),只是Go提供的一種語(yǔ)法糖。
其次,Go中數(shù)組的類(lèi)型,是由數(shù)值類(lèi)型和長(zhǎng)度兩個(gè)一起確定的。[2]int 和 [3]int 不是同一個(gè)類(lèi)型,不能進(jìn)行傳參和比較,把數(shù)組理解為類(lèi)型和長(zhǎng)度兩個(gè)屬性的結(jié)構(gòu)體,其實(shí)就一目了然了。
Go中的數(shù)組屬于值類(lèi)型,通常應(yīng)該存儲(chǔ)于棧中,局部變量依然會(huì)根據(jù)逃逸分析確定存儲(chǔ)棧還是堆中。
編譯器對(duì)數(shù)組函數(shù)中做兩種不同的優(yōu)化:
在靜態(tài)區(qū)完成賦值后復(fù)制到棧中。
總結(jié)起來(lái),在不考慮逃逸分析的情況下,如果數(shù)組中元素的個(gè)數(shù)小于或者等于 4 個(gè),那么所有的變量會(huì)直接在棧上初始化,如果數(shù)組元素大于 4 個(gè),變量就會(huì)在靜態(tài)存儲(chǔ)區(qū)初始化然后拷貝到棧上。
由于數(shù)組是值類(lèi)型,那么賦值和函數(shù)傳參操作都會(huì)復(fù)制整個(gè)數(shù)組數(shù)據(jù)。
不管是賦值或函數(shù)傳參,地址都不一致,發(fā)生了拷貝。如果數(shù)組的數(shù)據(jù)較大,則會(huì)消耗掉大量?jī)?nèi)存。那么為了減少拷貝我們可以主動(dòng)的傳遞指針呀。
地址是一樣的,不過(guò)傳指針會(huì)有一個(gè)弊端,從打印結(jié)果可以看到,指針地址都是同一個(gè),萬(wàn)一原數(shù)組的指針指向更改了,那么函數(shù)里面的指針指向都會(huì)跟著更改。
同樣的我們將數(shù)組轉(zhuǎn)換為切片,通過(guò)傳遞切片,地址是不一樣的,數(shù)組值相同。
切片是引用傳遞,所以它們不需要使用額外的內(nèi)存并且比使用數(shù)組更有效率。
所以,切片屬于引用類(lèi)型。
通過(guò)這種方式可以將數(shù)組轉(zhuǎn)換為切片。
中間不加三個(gè)點(diǎn)就是切片,使用這種方式創(chuàng)建切片,實(shí)際上是先創(chuàng)建數(shù)組,然后再通過(guò)第一種方式創(chuàng)建。
使用make創(chuàng)建切片,就不光編譯期了,make創(chuàng)建切片會(huì)涉及到運(yùn)行期。1. 切片的大小和容量是否足夠小;
切片是否發(fā)生了逃逸,最終在堆上初始化。如果切片小的話會(huì)先在棧或靜態(tài)區(qū)進(jìn)行創(chuàng)建。
切片有一個(gè)數(shù)組的指針,len是指切片的長(zhǎng)度, cap指的是切片的容量。
cap是在初始化切片是生成的容量。
發(fā)現(xiàn)切片的結(jié)構(gòu)體是數(shù)組的地址指針array unsafe.Pointer,而Go中數(shù)組的地址代表數(shù)組結(jié)構(gòu)體的地址。
slice 中得到一塊內(nèi)存地址,array[0]或者unsafe.Pointer(array[0])。
也可以通過(guò)地址構(gòu)造切片
nil切片:指的unsafe.Pointer 為nil
空切片:
創(chuàng)建的指針不為空,len和cap為空
當(dāng)一個(gè)切片的容量滿了,就需要擴(kuò)容了。怎么擴(kuò),策略是什么?
如果原來(lái)數(shù)組切片的容量已經(jīng)達(dá)到了最大值,再想擴(kuò)容, Go 默認(rèn)會(huì)先開(kāi)一片內(nèi)存區(qū)域,把原來(lái)的值拷貝過(guò)來(lái),然后再執(zhí)行 append() 操作。這種情況對(duì)現(xiàn)數(shù)組的地址和原數(shù)組地址不相同。
從上面結(jié)果我們可以看到,如果用 range 的方式去遍歷一個(gè)切片,拿到的 Value 其實(shí)是切片里面的值拷貝,即淺拷貝。所以每次打印 Value 的地址都不變。
由于 Value 是值拷貝的,并非引用傳遞,所以直接改 Value 是達(dá)不到更改原切片值的目的的,需要通過(guò) slice[index] 獲取真實(shí)的地址。
new 主要用于結(jié)構(gòu)體的初始化
make用于數(shù)組array,切片slice,協(xié)程chnnel的初始化
例如: users:=make([10]int);
msg:=make(chan int);
new會(huì)分配結(jié)構(gòu)空間,并初始化為清空為零,不進(jìn)一步初始化
new之后需要一個(gè)指針來(lái)指向這個(gè)結(jié)構(gòu)
make會(huì)分配結(jié)構(gòu)空間及其附屬空間,并完成其間的指針初始化
make返回這個(gè)結(jié)構(gòu)空間,不另外分配一個(gè)指針
例子new:
var p *[]int = new([]int)
或
p := new([]int)
以上分配了一個(gè)slice結(jié)構(gòu),但是結(jié)構(gòu)中的應(yīng)該指向底層數(shù)組的ptr指針為空,故實(shí)際不能往這個(gè)slice里面存取數(shù)據(jù)
同時(shí)分配了一個(gè)指針p,也即(在32位系統(tǒng)中)占4個(gè)字節(jié)并存放slice結(jié)構(gòu)的地址
例子make:
var v []int = make([]int, 0)
v := make([]int, 0)
以上分配了一個(gè)slice結(jié)構(gòu),且結(jié)構(gòu)中的應(yīng)該指向底層數(shù)組的ptr指針已經(jīng)指向了某個(gè)底層數(shù)組,這個(gè)底層數(shù)組應(yīng)該已經(jīng)分配了,故這個(gè)slice已經(jīng)可以使用了
注意v就是這個(gè)slice結(jié)構(gòu),而不是一個(gè)指向slice的指針
上述僅是示例,一般使用時(shí)都會(huì)明確長(zhǎng)度和容量:v := make([]int, 10, 50)
結(jié)論:
由上可見(jiàn),用new來(lái)分配slice的意義不大,因?yàn)闆](méi)有恰當(dāng)?shù)某跏蓟瑹o(wú)法直接使用
有附帶空間的結(jié)構(gòu),使用make來(lái)初始化,可以完成內(nèi)部指針初始化,其后可以立即使用
標(biāo)題名稱(chēng):go語(yǔ)言切片初始化,go語(yǔ)言的切片
網(wǎng)址分享:http://chinadenli.net/article11/dsgsjgd.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)、、定制開(kāi)發(fā)、網(wǎng)頁(yè)設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)