數(shù)據(jù)結(jié)構(gòu)之鏈表

鏈表分為單鏈表,雙向鏈表和循環(huán)鏈表

鏈表的時間復(fù)雜度

  • 插入 O(n)
  • 刪除 O(1)
  • 隨機訪問 O(n)

單雙鏈表比較

雙向鏈表優(yōu)于單鏈表的優(yōu)點是 可以在O(1)時間復(fù)雜度的情況下找到前驅(qū)節(jié)點沪编。這樣可以某些情況下快速的插入刪除操作比單鏈表簡單高效恕出。但是空間復(fù)雜度要比單鏈表高

其實時間復(fù)雜度和空間復(fù)雜度球及,是相輔相成的,以時間換空間 或者以空間換時間。 比如復(fù)雜度O(n)的排序(桶排序 基數(shù)排序等)比快排冒泡排序快就是因為占用了大量的空間蒋荚,在空間內(nèi)基本上有序,這樣就降低了時間復(fù)雜度馆蠕。

數(shù)組和鏈表的比較

數(shù)組是連續(xù)的內(nèi)存塊期升, 一經(jīng)聲明就要占用整塊的內(nèi)存空間, 如果聲明一個很大的數(shù)組互躬, 但是內(nèi)存中沒有那么大的連續(xù)空間則聲明失敗播赁, 但是鏈表則不存在這些問題。

bb這么多吼渡,來看go版本的代碼實現(xiàn)(go中有一個庫叫container已經(jīng)實現(xiàn)了鏈表這種數(shù)據(jù)結(jié)果可以拿來直接使用):

  • 完成基本的準(zhǔn)備工作:
// 節(jié)點結(jié)構(gòu)體
type ListNode struct {
    next *ListNode
    value interface{}
}

// 鏈表結(jié)構(gòu)體
type LinkedList struct {
    head *ListNode 
    length uint
}

func NewListNode(v interface{}) *ListNode {
    return &ListNode{nil, v}
}

func (this *ListNode) GetNext() *ListNode {
    return this.next
}

// 獲取節(jié)點值
func (this *ListNode) GetValue() interface{} {
    return this.value
}
// 穿件新的鏈表
func NewLinkedList() *LinkedList {
    return &LinkedList{NewListNode(0), 0}
}
  • 鏈表的操作:
// 插入 
func (this *LinkedList) InsertAfter(p *ListNode, v interface{}) bool {
    if nil == p {
        return false
    }
    // 斷開p的next容为,然后插入新的next 再連接到一起
    newNode := NewListNode(v)
    oldNext := p.GetNext()
    p.next = newNode
    newNode.next = oldNext
    this.length++
    return true
}

// 在某節(jié)點前方插入
func (this *LinkedList) InsertBefore(p *ListNode, v interface{}) bool {
    if nil == p || p == this.head {
        return false
    }
    cur := this.head.next
    pre := this.head
    
    for nil != cur {
        if cur == p {
            break
        }
        pre = cur 
        cur = cur.next
    }
    
    newNode := NewListNode(v)
    pre.next = newNode
    newNode.next = cur 
    this.length++
    return true
}

func (this *LinkedList) InsertToHead(v interface{}) bool {
    return this.InsertAfter(this.head, v)
}

func (this *LinkedList) InsertToTail(v interface{}) bool {
    cur := this.head
    for nil != cur.next {
        cur = cur.next
    }
    return this.InsertAfter(cur, v)
}
  • 查找操作
func (this *LinkedList) FindByIndex(index uint) *ListNode{
    if index >= this.length {
        return nil 
    }
    cur := this.head.next
    var i uint = 0
    for ; i<index; i++ {
        cur = cur.next
    }
    return cur
}
  • 刪除操作
// 通過操作兩個指針找到對應(yīng)的p然后斷開去掉p再重新連上。
func (this *LinkedList) DeleteNode(p *ListNode) bool {
    if p == nil {
        return false
    }
    cur := this.head.next
    pre := this.head
    for nil != cur {
        if cur == p {
            break
        }
        pre = cur 
        cur = cur.next
    }
    if nil == cur {
        return false
    }
    pre.next = p.next
    p = nil 
    this.length--
    return true 
}
  • 打印
func (this *LinkedList) Print() {
    cur := this.head.next
    format := ""
    for nil != cur {
        format += fmt.Sprintf("%+v", cur.GetValue())
        cur = cur.next
        if nil != cur {
            format += "->"
        }
        fmt.Println(format)
    }
}

鏈表的操作基本上實現(xiàn)。
如何讓鏈表能快速的查找坎背, 可以通過鏈表來實現(xiàn)跳表這種類似索引功能的數(shù)據(jù)結(jié)構(gòu)來增加查找速度竭缝。但是同樣的是以空間換時間。

判斷是否有環(huán)

func (this *LinkedList) HasCycle() bool {
    // 快慢指針判斷是否有環(huán) 
    if nil != this.head{
        slow := this.head
        fast := this.head.next
        for nil != fast && nil != fast.next {
            slow = slow.next
            fast = fast.next.next
            if slow == fast {
                return true
            }
        }
    }
    return false
}

判斷是否是回文字符串

func isPalindrome(l *LinkedList) bool {
    lLen := l.length
    if lLen == 0 {
        return false
    }
    if lLen == 1 {
        return true
    }

    s := make([]string, 0, lLen/2)
    cur := l.head
    for i := uint(1); i < lLen; i++ {
        // 先把前一半數(shù)據(jù)裝載到數(shù)組 進(jìn)行比較
        cur = cur.next
        if lLen % 2 != 0 && i == (lLen/2 + 1) {
            continue
        }
        if i <= lLen / 2 {
            s = append(s, cur.GetValue().(string))
        }else {
            if s[lLen - 1] != cur.GetValue().(string) {
                return false
            }
        }
    }
    return true
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沼瘫,一起剝皮案震驚了整個濱河市抬纸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌耿戚,老刑警劉巖湿故,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異膜蛔,居然都是意外死亡坛猪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門皂股,熙熙樓的掌柜王于貴愁眉苦臉地迎上來墅茉,“玉大人,你說我怎么就攤上這事呜呐【徒铮” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵蘑辑,是天一觀的道長洋机。 經(jīng)常有香客問我,道長洋魂,這世上最難降的妖魔是什么绷旗? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮副砍,結(jié)果婚禮上衔肢,老公的妹妹穿的比我還像新娘。我一直安慰自己豁翎,他們只是感情好角骤,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谨垃,像睡著了一般启搂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刘陶,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音牢撼,去河邊找鬼匙隔。 笑死,一個胖子當(dāng)著我的面吹牛熏版,可吹牛的內(nèi)容都是我干的纷责。 我是一名探鬼主播捍掺,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼再膳!你這毒婦竟也來了挺勿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤喂柒,失蹤者是張志新(化名)和其女友劉穎不瓶,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灾杰,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蚊丐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了艳吠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片麦备。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖昭娩,靈堂內(nèi)的尸體忽然破棺而出凛篙,到底是詐尸還是另有隱情,我是刑警寧澤栏渺,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布鞋诗,位于F島的核電站,受9級特大地震影響迈嘹,放射性物質(zhì)發(fā)生泄漏削彬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一秀仲、第九天 我趴在偏房一處隱蔽的房頂上張望融痛。 院中可真熱鬧,春花似錦神僵、人聲如沸雁刷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沛励。三九已至,卻和暖如春炮障,著一層夾襖步出監(jiān)牢的瞬間目派,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工胁赢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留企蹭,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像谅摄,于是被迫代替她去往敵國和親徒河。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

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