無(wú)標(biāo)題文章

Swift算法俱樂(lè)部:Swift 鏈表數(shù)據(jù)結(jié)構(gòu)@(Swift)在本教程中获搏,我們將會(huì)在Swift 3中實(shí)現(xiàn)鏈表常熙。##Getting Started鏈表是一個(gè)序列化的數(shù)據(jù)項(xiàng),每一個(gè)項(xiàng)目都作為節(jié)點(diǎn)(node)被引用裸卫。有兩個(gè)主要類型的鏈表:?jiǎn)蜗蜴湵砟够撸總€(gè)節(jié)點(diǎn)有一個(gè)指向到下一個(gè)節(jié)點(diǎn)的引用。
Alt text
Alt text
雙向鏈表队伟,每個(gè)節(jié)點(diǎn)各有一個(gè)向前和向后的節(jié)點(diǎn)的引用幽勒。
Alt text
Alt text
我們還需要去跟蹤鏈表的開頭和結(jié)尾,通常管這兩個(gè)指針叫做head和tail锈颗。
Alt text
Alt text
##Swift 3中實(shí)現(xiàn)鏈表這部分咪惠,我們將會(huì)在Swift 3中實(shí)現(xiàn)鏈表。記滓逃怠:鏈表是由節(jié)點(diǎn)組成的渠鸽。所以需要先創(chuàng)建基本節(jié)點(diǎn)類。創(chuàng)建一個(gè)全新的Swift Playground并且添加一個(gè)Class:swiftpublic class Node {}###值節(jié)點(diǎn)需要關(guān)聯(lián)一個(gè)值憨奸,在Node類的中括號(hào)中添加下面的代碼:swiftvar value: String init(value: String) { self.value = value}聲明了一個(gè)屬性凿试,它的名字叫做value似芝,是String類型板甘。在我們的app中這可能是你想存儲(chǔ)的類型。還聲明了一個(gè)初始化方法寞奸,需要初始化所有非可選的屬性在跳。###Next另外,還需要一個(gè)值瓷翻,每個(gè)節(jié)點(diǎn)都需要一個(gè)指針指向到鏈表中的下一個(gè)節(jié)點(diǎn)齐帚。在類中添加另外一個(gè)屬性:swiftvar next: Node?這里聲明了一個(gè)next屬性,它是Node類型童谒。注意next屬性是可選沪羔,因?yàn)樵阪湵碇械淖詈笠粋€(gè)節(jié)點(diǎn)不會(huì)指向任何的節(jié)點(diǎn)蔫饰。###Previous我們將會(huì)實(shí)現(xiàn)一個(gè)雙向鏈表愉豺,所以我們還需要一個(gè)指向之前節(jié)點(diǎn)的指針。在類中添加另外一個(gè)屬性:swiftweak var previous: Node?>注意:為了避免所有權(quán)的循環(huán)引用杖剪,聲明的previous指針是弱引用驰贷。如果你有一個(gè)節(jié)點(diǎn)A括袒,它的下一個(gè)節(jié)點(diǎn)是B,這樣A指向B锹锰,B也指向A漓库。在某些的情況下渺蒿,這樣會(huì)導(dǎo)致節(jié)點(diǎn)即使在被刪除以后還會(huì)存在的情況蘸嘶。這是我們所不希望的陪汽,所以需要讓其中的一個(gè)指針為弱引用來(lái)避免出現(xiàn)這樣的問(wèn)題。###鏈表現(xiàn)在已經(jīng)創(chuàng)建的節(jié)點(diǎn)還需要確定它的起點(diǎn)和終點(diǎn)况增。添加新的LinkedList類到playground的底部:swiftpublic class LinkedList { fileprivate var head: Node? private var tail: Node? public var isEmpty: Bool { return head == nil } public var first: Node? { return head } public var last: Node? { return tail }}這個(gè)類將會(huì)跟蹤鏈表的開頭和結(jié)尾训挡,同樣也會(huì)提供幾個(gè)有用的方法。###Append處理添加一個(gè)新的節(jié)點(diǎn)到鏈表为肮,我們將會(huì)在LinkedList類中聲明一個(gè)append(value:)方法颊艳。swiftpublic func append(value: String) { // 1 let newNode = Node(value: value) // 2 if let tailNode = tail { newNode.previous = tailNode tailNode.next = newNode } // 3 else { head = newNode } // 4 tail = newNode}回顧這部分的代碼:創(chuàng)建一個(gè)包含值的節(jié)點(diǎn)。記住忘分,創(chuàng)建Node類的目的是讓每一個(gè)項(xiàng)目都可以指向到之前或之后的節(jié)點(diǎn)妒峦。如果tailNode不為空,就意味著鏈表中有些東西窥浪,配置這個(gè)新的項(xiàng)目的previous指向到鏈表的tailNode笛丙,并且配置tailNode的next指向到新的項(xiàng)目。最后符相,設(shè)置鏈表的tail為最新創(chuàng)建的項(xiàng)目對(duì)象啊终。###打印鏈表讓我們?cè)囍敵鲦湵怼T贚inkedList類的外面:swiftlet dogBreeds = LinkedList()dogBreeds.append(value: "Labrador")dogBreeds.append(value: "Bulldog")dogBreeds.append(value: "Beagle")dogBreeds.append(value: "Husky")在定義鏈表的后面趟脂,嘗試打永堋:swiftprint(dogBreeds)你可以通過(guò)組合鍵:Command-Shift-Y啟動(dòng)調(diào)式控制臺(tái)佛玄,可以看到下面的輸出:LinkedList這種輸出沒(méi)有任何的價(jià)值,要想顯示更多的有用的文字信息般贼,可以讓LinkedList類采用CustomStringConvertable協(xié)議奥吩。在LinkedList類中實(shí)現(xiàn)下面的代碼:swift// 1extension LinkedList: CustomStringConvertible { // 2 public var description: String { // 3 var text = "[" var node = head // 4 while node != nil { text += "\(node!.value)" node = node!.next if node != nil { text += ", " } } // 5 return text + "]" }}上面代碼的意思是:1. 聲明了LinkedList類的擴(kuò)展哼蛆,并且采用CustomStringConvertible協(xié)議。這個(gè)協(xié)議希望你實(shí)現(xiàn)一個(gè)計(jì)算屬性description霞赫,該屬性是String類型腮介。2. 聲明的description屬性是計(jì)算屬性,它是一個(gè)只讀的并且返回字符串的屬性端衰。3. 聲明的text變量叠洗,它會(huì)生成整個(gè)的字符串。現(xiàn)在它包含一個(gè)左中括號(hào)靴迫,然后是鏈表的開始惕味。4. 通過(guò)循環(huán)鏈表楼誓,將鏈表中項(xiàng)目的值依次添加到text中玉锌。5. 添加一個(gè)右中括號(hào)到text變量∨备現(xiàn)在榄融,當(dāng)你調(diào)用LinkedList類的print方法涎才,將會(huì)看到一個(gè)非常美妙的鏈表描述:"[Labrador, Bulldog, Beagle, Husky]"###訪問(wèn)節(jié)點(diǎn)盡管通過(guò)鏈表的next和previous方法可以很有效的去按順序獲取每個(gè)節(jié)點(diǎn)耍铜,但有的時(shí)候通過(guò)索引的方式對(duì)于我們來(lái)說(shuō)可能會(huì)更加的簡(jiǎn)單棕兼。我們會(huì)在LinkedList類中聲明一個(gè)nodeAt(index: )方法靶衍,它將返回一個(gè)指定索引的節(jié)點(diǎn)颅眶。 修改LinkedList中的代碼:swiftpublic func nodeAt(index: Int) -> Node? { // 1 if index >= 0 { var node = head var i = index // 2 while node != nil { if i == 0 { return node } i -= 1 node = node!.next } } // 3 return nil}上面的代碼是這樣的:1. 添加對(duì)指定索引值的檢測(cè)帚呼,看它是否為非負(fù)數(shù)。這樣可以防止負(fù)數(shù)出現(xiàn)的無(wú)限循環(huán)沈自。2. 循環(huán)節(jié)點(diǎn)枯途,直到到達(dá)了那個(gè)指定索引值的節(jié)點(diǎn)酪夷,就會(huì)返回這個(gè)node晚岭。3. 如果索引值小于0,或者是大于鏈表的項(xiàng)目數(shù)片择,則會(huì)返回nil字管。###移除所有節(jié)點(diǎn)移除所有節(jié)點(diǎn)脐供,我們只需要讓head和tail為nil即可政己。swiftpublic func removeAll() { head = nil tail = nil}###移除單個(gè)節(jié)點(diǎn)移除單個(gè)節(jié)點(diǎn),我們需要考慮下面的三種情況:1. 移除第一個(gè)節(jié)點(diǎn)沦泌,需要修改head和previous指針:
Alt text
Alt text
2. 移除中間的節(jié)點(diǎn)谢谦,需要修改previous和next:
Alt text
Alt text
3. 移除最后節(jié)點(diǎn)回挽,需要修改next和tail指針:
Alt text
Alt text
修改LinkedList類:swiftpublic func remove(node: Node) -> String { let prev = node.previous let next = node.next if let prev = prev { prev.next = next // 1 } else { head = next // 2 } next?.previous = prev // 3 if next == nil { tail = prev // 4 } // 5 node.previous = nil node.next = nil // 6 return node.value}1. 如果移除的節(jié)點(diǎn)不是第一節(jié)點(diǎn)則修改next指針。2. 如果移除的節(jié)點(diǎn)是第一節(jié)點(diǎn)則修改head墙牌。3. 修改刪除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)的previous喜滨。4. 如果刪除的是最后一個(gè)節(jié)點(diǎn),修改tail焰情。5. 給刪除節(jié)點(diǎn)的previous和next賦值nil。6. 返回移除節(jié)點(diǎn)的值初橘。##Generics之前耕蝉,我們已經(jīng)實(shí)現(xiàn)了可以存儲(chǔ)字符串的基本鏈表類垒在。已經(jīng)提供了添加、移除和訪問(wèn)節(jié)點(diǎn)的功能踢关。這部分签舞,我們將會(huì)使用范式抽象出所有的類型鏈表。修改之前的Node類:swift// 1public class Node<T> { // 2 var value: T var next: Node<T>? weak var previous: Node<T>? // 3 init(value: T) { self.value = value }}1. 改變Node類的聲明為范式類型T师妙。2. 我們的目的是允許Node類存儲(chǔ)任何的類型默穴,所以構(gòu)建value的類型也為T蓄诽,而不是之前的String。3. 修改初始化方法锯岖。修改LinkedList類使用范式出吹。swift// 1. Change the declaration of the Node class to take a generic type Tpublic class LinkedList<T> { // 2. Change the head and tail variables to be constrained to type T fileprivate var head: Node<T>? private var tail: Node<T>? public var isEmpty: Bool { return head == nil } // 3. Change the return type to be a node constrained to type T public var first: Node<T>? { return head } // 4. Change the return type to be a node constrained to type T public var last: Node<T>? { return tail } // 5. Update the append function to take in a value of type T public func append(value: T) { let newNode = Node(value: value) if let tailNode = tail { newNode.previous = tailNode tailNode.next = newNode } else { head = newNode } tail = newNode } // 6. Update the nodeAt function to return a node constrained to type T public func nodeAt(index: Int) -> Node<T>? { if index >= 0 { var node = head var i = index while node != nil { if i == 0 { return node } i -= 1 node = node!.next } } return nil } public func removeAll() { head = nil tail = nil } // 7. Update the parameter of the remove function to take a node of type T. Update the return value to type T. public func remove(node: Node<T>) -> T { let prev = node.previous let next = node.next if let prev = prev { prev.next = next } else { head = next } next?.previous = prev if next == nil { tail = prev } node.previous = nil node.next = nil return node.value }}所有代碼已經(jīng)完成秋麸,可以實(shí)地測(cè)試了:swiftlet dogBreeds = LinkedList<String>()dogBreeds.append(value: "Labrador")dogBreeds.append(value: "Bulldog")dogBreeds.append(value: "Beagle")dogBreeds.append(value: "Husky") let numbers = LinkedList<Int>()numbers.append(value: 5)numbers.append(value: 10)numbers.append(value: 15)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市可缚,隨后出現(xiàn)的幾起案子城看,更是在濱河造成了極大的恐慌测柠,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡驮俗,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)百姓,“玉大人端圈,你說(shuō)我怎么就攤上這事÷匦幔” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)地沮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)雷袋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上捅僵,老公的妹妹穿的比我還像新娘。我一直安慰自己馒闷,他們只是感情好逛薇,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般羞福。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上看靠,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音谤祖,去河邊找鬼。 笑死额湘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的毯焕。 我是一名探鬼主播婆咸,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼物遇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了诗舰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后渔呵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年示启,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了迟螺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锉桑。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡球订,死狀恐怖微驶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扶檐,我是刑警寧澤款筑,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布哮翘,位于F島的核電站阻课,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏署驻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兆解,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)岂丘。三九已至,卻和暖如春寨蹋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背运褪。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工攀芯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侣诺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓灭忠,卻偏偏與公主長(zhǎng)得像涕蜂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子有鹿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容