golang雙鏈表的實現

雙鏈表的實現

基本概念

每個節點都存儲上一個和下一個節點的指針

實現思路

建立一個節點結構體
  1. 每一個節點都有上節點指針與下節點指針
  2. 每一個節點都有一個key => value
建立一個鏈表結構體
  1. 鏈表容量大小屬性
  2. 鏈表大小屬性
  3. 鏈表鎖, 實現併發安全
  4. 鏈表頭節點
  5. 鏈表尾節點
實現鏈表操做方法
  1. 添加頭部節點操做AppendHead
  2. 添加尾部節點操做AppendTail
  3. 追加尾部節點操做Append
  4. 插入任意節點操做Insert
  5. 刪除任意節點操做Remove
  6. 刪除頭部節點操做RemoveHead
  7. 刪除尾部節點操做RemoveTail
  8. 獲取指定位置的節點Get
  9. 搜索任意節點Search
  10. 獲取鏈表大小GetSize
  11. 打印全部節點操做Print
  12. 反轉全部節點操做Reverse

總結

  1. 學好算法是一個不斷積累的過程
  2. 學習時還需作到知行合一
  3. 實現時須要多作用例測試.

代碼解析

定義節點的結構體

type DoubleNode struct {
    Key   int         //鍵
    Value interface{} //值
    Prev  *DoubleNode //上一個節點指針
    Next  *DoubleNode //下一個節點指針
    Freq  int         //頻率次數.爲了給LFU使用的
}

定義一個雙鏈表的結構體

//定義一個雙鏈表的結構
type DoubleList struct {
    lock     *sync.RWMutex //鎖
    Capacity uint          //最大容量
    Size     uint          //當前容量
    Head     *DoubleNode   //頭節點
    Tail     *DoubleNode   //尾部節點
}

初使雙鏈表

//初使雙鏈表
func New(capacity uint) *DoubleList {
    list := new(DoubleList)
    list.Capacity = capacity
    list.lock = new(sync.RWMutex)
    list.Size = 0
    list.Head = nil
    list.Tail = nil
    return list
}

添加頭部節點

實現思路
  1. 先判斷容量大小
  2. 判斷頭部是否爲空,node

    1. 若是爲空則添加新節點
    2. 若是不爲空則更改現有的節點,並添加上
func (list *DoubleList) AddHead(node *DoubleNode) bool {
    //判斷容量是否爲0
    if list.Capacity == 0 {
        return false
    }
    list.lock.Lock()
    defer list.lock.Unlock()
    //判斷頭部節點是否爲nil
    if list.Head == nil {
        list.Head = node
        list.Tail = node
    } else { //存在頭部節點
        list.Head.Prev = node //將舊頭部節點上一個節點指向新節點
        node.Next = list.Head //新頭部節點下一個節點指向舊頭部節點
        list.Head = node      //設置新的頭部節點
        list.Head.Prev = nil  //將新的頭部節點上一個節點設置NIL
    }
    list.Size++
    return true
}

添加尾部元素

實現思路
  1. 先判斷容量大小
  2. 判斷尾部是否爲空,git

    1. 若是爲空則添加新節點
    2. 若是不爲空則更改現有的節點,並添加上
func (list *DoubleList) AddTail(node *DoubleNode) bool {
    //判斷是否有容量,
    if list.Capacity == 0 {
        return false
    }
    list.lock.Lock()
    defer list.lock.Unlock()
    //判斷尾部是否爲空
    if list.Tail == nil {
        list.Tail = node
        list.Head = node
    } else {
        //舊的尾部下個節點指向新節點
        list.Tail.Next = node
        //追加新節點時,先將node的上節點指向舊的尾部節點
        node.Prev = list.Tail
        //設置新的尾部節點
        list.Tail = node
        //新的尾部下個節點設置爲空
        list.Tail.Next = nil
    }
    //雙鏈表大小+1
    list.Size++
    return true
}

添加任意位置元素

實現思路
  1. 判斷容量大小
  2. 判斷鏈表大小
  3. 第一種: 若是插入的位置大於當前長度則尾部添加
  4. 第二種: 若是插入的位置等於0則,頭部添加
  5. 第三種: 中間插入節點github

    1. 先取出要插入位置的節點,假調爲C節點
    2. 介於A, C之間, 插入一個B節點
    3. A的下節點應該是B, 即C的上節點的下節點是B
    4. B的上節點是C的上節點
    5. B的下節點是C
//添加任意位置元素
func (list *DoubleList) Insert(index uint, node *DoubleNode) bool {
    //容量滿了
    if list.Size == list.Capacity {
        return false
    }
    //若是沒有節點
    if list.Size == 0 {
        return list.Append(node)
    }
    //若是插入的位置大於當前長度則尾部添加
    if index > list.Size {
        return list.AddTail(node)
    }
    //若是插入的位置等於0則,頭部添加
    if index == 0 {
        return list.AddHead(node)
    }
    //取出要插入位置的節點
    nextNode := list.Get(index)
    list.lock.Lock()
    defer list.lock.Unlock()
    //中間插入:
    //假設已有A, C節點, 如今要插入B節點
    // nextNode便是C節點,
    //A的下節點應該是B, 即C的上節點的下節點是B
    nextNode.Prev.Next = node
    //B的上節點是C的上節點
    node.Prev = nextNode.Prev
    //B的下節點是C
    node.Next = nextNode
    //C的上節點是B
    nextNode.Prev = node
    list.Size++
    return true
}

刪除頭部節點

實現思路
  1. 判斷頭部是否爲空
  2. 將頭部節點取出來
  3. 判斷頭部是否有下一個節點算法

    1. 沒有下一個節點,則說明只有一個節點, 刪除自己,無須移動指針位置
    2. 若是有下一個節點,則頭部下一個節點便是頭部節點.
//刪除頭部節點
func (list *DoubleList) RemoveHead() *DoubleNode {
    //判斷頭部節點是否爲空
    if list.Head == nil {
        return nil
    }
    list.lock.Lock()
    defer list.lock.Unlock()
    //將頭部節點取出來
    node := list.Head
    //判斷頭部是否有下一個節點
    if node.Next != nil {
        list.Head = node.Next
        list.Head.Prev = nil
    } else { //若是沒有下一個節點, 說明只有一個節點
        list.Head, list.Tail = nil, nil
    }
    list.Size--
    return node
}

刪除尾部節點

實現思路
  1. 判斷尾部節點是否爲空
  2. 取出尾部節點
  3. 判斷尾部節點的上一個節點是否存在安全

    1. 不存在:則說明只有一個節點, 刪除自己,無須移動指針位置
    2. 若是存在上一個節點,則尾部的上一個節點便是尾部節點.
//刪除尾部節點
func (list *DoubleList) RemoveTail() *DoubleNode {
    //判斷尾部節點是否爲空
    if list.Tail == nil {
        return nil
    }
    list.lock.Lock()
    defer list.lock.Unlock()
    //取出尾部節點
    node := list.Tail
    //判斷尾部節點的上一個是否存在
    if node.Prev != nil {
        list.Tail = node.Prev
        list.Tail.Next = nil
    }
    list.Size--
    return node
}

刪除任意元素

實現思路
  1. 判斷是不是頭部節點
  2. 判斷是不是尾部節點
  3. 不然爲中間節點,須要移動上下節點的指針位置.並實現元素刪除併發

    1. 將上一個節點的下一節點指針指向下節點
    2. 將下一個節點的上一節點指針指向上節點
//刪除任意元素
func (list *DoubleList) Remove(node *DoubleNode) *DoubleNode {
    //判斷是不是頭部節點
    if node == list.Head {
        return list.RemoveHead()
    }
    //判斷是不是尾部節點
    if node == list.Tail {
        return list.RemoveTail()
    }
    list.lock.Lock()
    defer list.lock.Unlock()
    //節點爲中間節點
    //則須要:
    //將上一個節點的下一節點指針指向下節點
    //將下一個節點的上一節點指針指向上節點
    node.Prev.Next = node.Next
    node.Next.Prev = node.Prev
    list.Size--
    return node
}

查看完整源碼

相關文章
相關標籤/搜索