欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解go語言單鏈表及其常用方法的實(shí)現(xiàn)

 更新時間:2020年11月30日 09:31:52   作者:Zppj  
這篇文章主要介紹了詳解go語言單鏈表及其常用方法的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

目的

在刷算法題中經(jīng)常遇到關(guān)于鏈表的操作,在使用go語言去操作鏈表時不熟悉其實(shí)現(xiàn)原理,目的是為了重溫鏈表這一基礎(chǔ)且關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)。

1、鏈表的特點(diǎn)和初始化

1.1、鏈表的特點(diǎn)
用一組任意的存儲單元存儲線性表的數(shù)據(jù)元素(這組存儲單元可以是連續(xù)的,也可以是不連續(xù)的)

1.2、結(jié)點(diǎn)

結(jié)點(diǎn)(node)

  • 數(shù)據(jù)域 => 存儲元素信息
  • 指針域 => 存儲結(jié)點(diǎn)的直接后繼,也稱作指針或鏈

首元結(jié)點(diǎn) 是指鏈表中存儲的第一個數(shù)據(jù)元素的結(jié)點(diǎn)
頭結(jié)點(diǎn) 是在首元結(jié)點(diǎn)之前附設(shè)的一個結(jié)點(diǎn),其指針域指向首元結(jié)點(diǎn)(非必須)
頭指針 是指向鏈表中第一個結(jié)點(diǎn)的指針


1.3、單鏈表
特點(diǎn)

  • 每個結(jié)點(diǎn)中只包含一個指針域
  • 單鏈表是非隨機(jī)存取的存儲結(jié)構(gòu),要取得第i個數(shù)據(jù)元素必須從頭指針出發(fā),順鏈進(jìn)行尋找,也稱為順序存取的存取結(jié)構(gòu)

1.4、單鏈表的常用操作

本文主要實(shí)現(xiàn)了單鏈表的以下操作

  • 判斷是否為空
  • 獲取鏈表長度
  • 在頭部插入元素
  • 在尾部插入元素
  • 刪除指定位置元素
  • 刪除指定值的元素
  • 查找是否包含指定值
  • 查找指定位置元素的值
  • 遍歷鏈表所有結(jié)點(diǎn)

1.5、單鏈表的初始化

//定義單鏈表結(jié)構(gòu)體
type Node struct {
  data interface{} //數(shù)據(jù)域
  next *Node    //指針域
}
type List struct {
  length  int //儲存鏈表的長度
  headNode *Node
}

/*單鏈表的初始化
1、生成新結(jié)點(diǎn)作為頭結(jié)點(diǎn),用頭指針指向頭結(jié)點(diǎn)
2、頭結(jié)點(diǎn)的指針域置空
*/
func InitList() *List {
  //即構(gòu)造一個空的單鏈表L(包含頭指針)
  node := new(Node)
  L := new(List)
  L.headNode = node
  return L
}

2、單鏈表的插入

先講單鏈表的插入有利于后續(xù)相關(guān)操作的實(shí)現(xiàn)

2.1、在指定位置插入元素

/*單鏈表的插入=>將值為e的新結(jié)點(diǎn)插入到表的第i個結(jié)點(diǎn)的位置上,即插入到結(jié)點(diǎn)a(i-1)與a(i)之間
1、查找結(jié)點(diǎn)a(i-1)并由指針p指向該結(jié)點(diǎn)
2、生成一個新結(jié)點(diǎn)*s
3、將新結(jié)點(diǎn)*s的數(shù)據(jù)域置為e
4、將新結(jié)點(diǎn)*s的指針域指向結(jié)點(diǎn)a(i)
5、將結(jié)點(diǎn)*p的指針域指向新結(jié)點(diǎn)*s
*/
func (list *List) InsertElem(index int, v interface{}) {
  if index <= 0 || index > list.length {
    fmt.Println("err")
  } else {
    pre := list.headNode
    node := &Node{data: v}
    if index == 1 {
      node.next = pre
      list.headNode = node
    } else {
      for count := 1; count < index-1; count++ {
        pre = pre.next
      }
      node.next = pre.next
      pre.next = node
    }
    list.length--
  }
}

2.2、在頭部插入元素

func (list *List) AddElem(v interface{}) {
  node := &Node{data: v}
  if list.IsNull() { //處理空表的插入,否則會導(dǎo)致一個空的頭結(jié)點(diǎn)后移
    list.headNode = node
    list.length++
    return
  }
  node.next = list.headNode
  list.headNode = node
  list.length++
  return
}

2.3、在尾部插入元素

func (list *List) AppendElem(v interface{}) {
  node := &Node{data: v}
  if list.IsNull() {
    list.headNode.next = node
  } else {
    cur := list.headNode
    for cur.next != nil {
      cur = cur.next
    }
    cur.next = node
  }
  list.length++
  return
}

3、單鏈表的刪除

3.1、刪除指定值的元素

/*單鏈表的刪除
1、查找結(jié)點(diǎn)a(i-1)并由指針p指向該結(jié)點(diǎn)
2、臨時保存待刪除結(jié)點(diǎn)a(i)的地址在q中,以備釋放
3、將結(jié)點(diǎn)*p的指針域指向a(i)的直接后繼結(jié)點(diǎn)
4、釋放結(jié)點(diǎn)a(i)的空間
*/
func (list *List) DeleteElem(index int) {
  if index <= 0 || index > list.length {
    fmt.Println("刪除位置不合理")
    return
  } else {
    pre := list.headNode
    if index == 1 {
      list.headNode = pre.next
    } else {
      pre := list.headNode
      for count := 1; count < index-1; count++ {
        pre = pre.next
      }
      pre.next = pre.next.next
    }
    list.length--
  }
}

3.2、刪除指定位置的元素

func (list *List) RemoveElem(v interface{}) {
  pre := list.headNode
  if pre.data == v {
    list.headNode = pre.next
    fmt.Println("ok")
  } else {
    for pre.next != nil {
      if pre.next.data == v {
        pre.next = pre.next.next
        fmt.Println("ok")
        return
      } else {
        pre = pre.next
      }
    }
    fmt.Println("fail")
    return
  }
}

4、單鏈表的查詢

4.1、查找是否包含指定值

/*單鏈表的按值查找
1、用指針p指向首元結(jié)點(diǎn)
2、從首元結(jié)點(diǎn)開始以此順著鏈域next向下查找,只要指向當(dāng)前結(jié)點(diǎn)的指針p不為空,
并且p所指結(jié)點(diǎn)的數(shù)據(jù)域不等于給定值e,則執(zhí)行以下操作:p指向下一個結(jié)點(diǎn)
3、返回p。若查找成功,p此時即為結(jié)點(diǎn)的地址值,若查找失敗,p的值即為NULL。
*/
func (list *List) LocateElem(v interface{}) bool {
  if IsNull() {
    fmt.Println("err")
  } else {
    pre := list.headNode
    for pre != nil {
      if pre.data == v {
        return true
      }
      pre = pre.next
    }
    return false
  }
}

4.2、查找指定位置的值

/*單鏈表的取值
1、用指針P指向首元結(jié)點(diǎn),用j做計數(shù)器初值賦為1
2、從首元結(jié)點(diǎn)開始依次順著鏈域(指針域)next向下訪問,
只要指向當(dāng)前結(jié)點(diǎn)的指針P不為空,并且沒有達(dá)到序號為i的結(jié)點(diǎn),則循環(huán)執(zhí)行以下操作:
  2.1、P指向下一個結(jié)點(diǎn)
  2.2、計數(shù)器j相應(yīng)加1
3、退出循環(huán)時,如果指針P為空,或者計數(shù)器j大于i,說明指定的序號i值不合法(i大于表長n或i小于等于0),
取值失敗返回ERROR;否則取值成功,
此時j==i時,P所指的結(jié)點(diǎn)就是要找的第i個結(jié)點(diǎn),用參數(shù)e保存當(dāng)前結(jié)點(diǎn)的數(shù)據(jù)域,返回OK
*/
func (list *List) GetElem(index int) int {
  if index <= 0 || index > list.length {
    fmt.Println("err")
    return
  } else {
    pre := list.headNode
    for j := 0; j < index; j++ {
      if pre != nil {
        pre = pre.next
      }
    }
    return pre.data
  }
}

4.3、遍歷單鏈表

func (list *List) ShowList() {
  if !list.IsNull() {
    cur := list.headNode
    for {
      fmt.Printf("\t%v", cur.data)
      if cur.next != nil {
        cur = cur.next
      } else {
        break
      }
    }
  }
}

5、完整代碼及結(jié)果展示

package main

import "fmt"

//定義單鏈表結(jié)構(gòu)體

type Node struct {
  data interface{} //數(shù)據(jù)域
  next *Node    //指針域
}
type List struct {
  length  int //儲存鏈表的長度
  headNode *Node
}

/*
type Method interface {
  IsNull() bool          //1、判斷是否為空
  GetLength() int         //2、獲取鏈表長度
  InsertElem(i int, v interface{}) //3、在指定位置添加元素
  AddElem(v interface{})      //4、在頭部插入元素
  AppendElem(v interface{})    //5、在尾部插入元素
  DeleteElem(i int)        //6、刪除指定位置元素
  RemoveElem(v interface{})    //7、刪除指定值的元素
  ContaineElem(v interface{}) bool //8、是否包含指定值的元素
  LocateElem(i int) interface{}  //9、查找指定位置元素的值
  ShowList()            //10、遍歷鏈表所有結(jié)點(diǎn)
}
*/
/*單鏈表的初始化
1、生成新結(jié)點(diǎn)作為頭結(jié)點(diǎn),用頭指針指向頭結(jié)點(diǎn)
2、頭結(jié)點(diǎn)的指針域置空
*/
func InitList() *List {
  //即構(gòu)造一個空的單鏈表L(包含頭指針)
  node := new(Node)
  L := new(List)
  L.headNode = node
  return L
}

/*單鏈表的取值
1、用指針P指向首元結(jié)點(diǎn),用j做計數(shù)器初值賦為1
2、從首元結(jié)點(diǎn)開始依次順著鏈域(指針域)next向下訪問,只要指向當(dāng)前結(jié)點(diǎn)的指針P不為空,
并且沒有達(dá)到序號為i的結(jié)點(diǎn),則循環(huán)執(zhí)行以下操作:
  2.1、P指向下一個結(jié)點(diǎn)
  2.2、計數(shù)器j相應(yīng)加1
3、退出循環(huán)時,如果指針P為空,或者計數(shù)器j大于i,說明指定的序號i值
不合法(i大于表長n或i小于等于0),取值失敗返回ERROR;否則取值成功,
此時j==i時,P所指的結(jié)點(diǎn)就是要找的第i個結(jié)點(diǎn),用參數(shù)e保存當(dāng)前結(jié)點(diǎn)的數(shù)據(jù)域,返回OK
*/
func (list *List) GetElem(index int) int {
  if index <= 0 || index > list.length {
    return 0
  } else {
    pre := list.headNode
    for j := 0; j < index-1; j++ {
      if pre != nil {
        pre = pre.next
      }
    }
    return pre.data.(int)
  }
}

/*單鏈表的按值查找
1、用指針p指向首元結(jié)點(diǎn)
2、從首元結(jié)點(diǎn)開始以此順著鏈域next向下查找,只要指向當(dāng)前結(jié)點(diǎn)的
指針p不為空,并且p所指結(jié)點(diǎn)的數(shù)據(jù)域不等于給定值e,則執(zhí)行以下操作:
  2.1、p指向下一個結(jié)點(diǎn)
3、返回p。若查找成功,p此時即為結(jié)點(diǎn)的地址值,若查找失敗,p的值即為NULL。
*/
func (list *List) LocateElem(v interface{}) bool {
  if list.IsNull() {
    fmt.Println("err")
    return false
  } else {
    pre := list.headNode
    for pre != nil {
      if pre.data == v {
        return true
      }
      pre = pre.next
    }
    return false
  }
}

/*單鏈表的插入=>將值為e的新結(jié)點(diǎn)插入到表的第i個結(jié)點(diǎn)的位置上,即插入到結(jié)點(diǎn)a(i-1)與a(i)之間
1、查找結(jié)點(diǎn)a(i-1)并由指針p指向該結(jié)點(diǎn)
2、生成一個新結(jié)點(diǎn)*s
3、將新結(jié)點(diǎn)*s的數(shù)據(jù)域置為e
4、將新結(jié)點(diǎn)*s的指針域指向結(jié)點(diǎn)a(i)
5、將結(jié)點(diǎn)*p的指針域指向新結(jié)點(diǎn)*s
*/
func (list *List) InsertElem(index int, v interface{}) {
  if index <= 0 || index > list.length {
    fmt.Println("err")
  } else {
    pre := list.headNode
    node := &Node{data: v}
    if index == 1 {
      node.next = pre
      list.headNode = node
    } else {
      for count := 1; count < index-1; count++ {
        pre = pre.next
      }
      node.next = pre.next
      pre.next = node
    }
    list.length--
  }
}

/*單鏈表的刪除
1、查找結(jié)點(diǎn)a(i-1)并由指針p指向該結(jié)點(diǎn)
2、臨時保存待刪除結(jié)點(diǎn)a(i)的地址在q中,以備釋放
3、將結(jié)點(diǎn)*p的指針域指向a(i)的直接后繼結(jié)點(diǎn)
4、釋放結(jié)點(diǎn)a(i)的空間
*/
func (list *List) DeleteElem(index int) {
  if index <= 0 || index > list.length {
    fmt.Println("刪除位置不合理")
    return
  } else {
    pre := list.headNode
    if index == 1 {
      list.headNode = pre.next
    } else {
      pre := list.headNode
      for count := 1; count < index-1; count++ {
        pre = pre.next
      }
      pre.next = pre.next.next
    }
    list.length--
  }
}

func (list *List) RemoveElem(v interface{}) {
  pre := list.headNode
  if pre.data == v {
    list.headNode = pre.next
  } else {
    for pre.next != nil {
      if pre.next.data == v {
        pre.next = pre.next.next
        return
      } else {
        pre = pre.next
      }
    }
    fmt.Println("fail")
    return
  }
}

func (list *List) IsNull() bool {
  if list.length == 0 {
    return true
  } else {
    return false
  }
}

func (list *List) AddElem(v interface{}) {
  node := &Node{data: v}
  if list.IsNull() { //處理空表的插入,否則會導(dǎo)致一個空的頭結(jié)點(diǎn)后移
    list.headNode = node
    list.length++
    return
  }
  node.next = list.headNode
  list.headNode = node
  list.length++
  return
}

func (list *List) AppendElem(v interface{}) {
  node := &Node{data: v}
  if list.IsNull() {
    list.headNode.next = node
  } else {
    cur := list.headNode
    for cur.next != nil {
      cur = cur.next
    }
    cur.next = node
  }
  list.length++
  return
}

func (list *List) ShowList() {
  if !list.IsNull() {
    cur := list.headNode
    for {
      fmt.Printf("\t%v", cur.data)
      if cur.next != nil {
        cur = cur.next
      } else {
        break
      }
    }
    fmt.Printf("\n")
  }
}

func main() {
  L := InitList()
  msg := []int{12, 5, 3, 8, 55, 13}
  for i := range msg {
    L.AddElem(msg[i])
  }
  fmt.Println("---- 添加元素 ----")
  L.AppendElem(66)
  L.ShowList()
  fmt.Println("---- 按位刪除元素 ----")
  L.DeleteElem(3)
  L.ShowList()
  fmt.Println("---- 按值刪除元素 ----")
  L.RemoveElem(13)
  L.ShowList()
  fmt.Println("---- 插入元素 ----")
  L.InsertElem(1, 88)
  L.ShowList()
  fmt.Println("---- 按值尋找元素 ----")
  fmt.Println(L.LocateElem(88))
  fmt.Println("---- 按位尋找元素 ----")
  fmt.Println(L.GetElem(4))
}

結(jié)果
---- 添加元素 ----
        13      55      8       3       5       12      66
---- 按位刪除元素 ----
        13      55      3       5       12      66
---- 按值刪除元素 ----
        55      3       5       12      66
---- 插入元素 ----
        88      55      3       5       12      66
---- 按值尋找元素 ----
true
---- 按位尋找元素 ----
5

6、總結(jié)

本文中除了初始化時為鏈表添加了一個空的頭結(jié)點(diǎn),其他情況下均無頭結(jié)點(diǎn),正如書中所說,為單鏈表添加頭結(jié)點(diǎn)會方便很多,對鏈表進(jìn)行相關(guān)操作時,不需要對首元結(jié)點(diǎn)做額外的處理,也便于對空表和非空表做統(tǒng)一處理
關(guān)于刪除時釋放結(jié)點(diǎn)空間及指針回收,我們交由go強(qiáng)大的垃圾回收來完成

參考博客
Golang之單鏈表實(shí)現(xiàn)
go語言實(shí)現(xiàn)單鏈表

到此這篇關(guān)于詳解go語言單鏈表及其常用方法的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)go語言單鏈表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解

    詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解

    這篇文章主要為大家介紹了詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Go之集合slice的實(shí)現(xiàn)

    Go之集合slice的實(shí)現(xiàn)

    本文主要介紹了Go之集合slice的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Go+Vue開發(fā)一個線上外賣應(yīng)用的流程(用戶名密碼和圖形驗(yàn)證碼)

    Go+Vue開發(fā)一個線上外賣應(yīng)用的流程(用戶名密碼和圖形驗(yàn)證碼)

    這篇文章主要介紹了Go+Vue開發(fā)一個線上外賣應(yīng)用(用戶名密碼和圖形驗(yàn)證碼),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Go語言struct類型詳解

    Go語言struct類型詳解

    這篇文章主要介紹了Go語言struct類型詳解,struct是一種數(shù)據(jù)類型,可以用來定義自己想的數(shù)據(jù)類型,需要的朋友可以參考下
    2014-10-10
  • GoLang中panic和recover作用詳解

    GoLang中panic和recover作用詳解

    panic?和?recover?是?Go?語言中用于處理異常和錯誤的機(jī)制,能夠幫助我們應(yīng)對意外情況并使程序更加健壯,這篇文章主要介紹了GoLang中panic和recover作用詳解,需要的朋友可以參考下
    2024-05-05
  • 解決Go語言time包數(shù)字與時間相乘的問題

    解決Go語言time包數(shù)字與時間相乘的問題

    這篇文章主要介紹了Go語言time包數(shù)字與時間相乘的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • gin框架Context如何獲取Get?Query?Param函數(shù)數(shù)據(jù)

    gin框架Context如何獲取Get?Query?Param函數(shù)數(shù)據(jù)

    這篇文章主要為大家介紹了gin框架Context?Get?Query?Param函數(shù)獲取數(shù)據(jù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Go設(shè)計模式之單例模式圖文詳解

    Go設(shè)計模式之單例模式圖文詳解

    單例模式是一種創(chuàng)建型設(shè)計模式,讓你能夠保證一個類只有一個實(shí)例,并提供一個訪問該實(shí)例的全局節(jié)點(diǎn),本文就通過圖文給大家介紹一下Go的單例模式,需要的朋友可以參考下
    2023-07-07
  • Golang常用包使用介紹

    Golang常用包使用介紹

    標(biāo)準(zhǔn)的Go語言代碼庫中包含了大量的包,并且在安裝Go的時候多數(shù)會自動安裝到系統(tǒng)中。我們可以在$GOROOT/src/pkg目錄中查看這些包。下面簡單介紹一些我們開發(fā)中常用的包
    2022-09-09
  • Golang如何快速刪除map所有元素

    Golang如何快速刪除map所有元素

    這篇文章主要介紹了Golang如何快速刪除map所有元素問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11

最新評論