• GoLang 数据结构-单向链表,双向链表,单向环形链表


    • 单向链表

      1 package main
      2 
      3 import (
      4     "fmt"
      5     "os"
      6 )
      7 
      8 //HeroNode 英雄结构体
      9 type HeroNode struct {
     10     Nom      int
     11     Name     string
     12     NickName string
     13     Next     *HeroNode
     14 }
     15 
     16 //InsertHeroNode 插入英雄结点 方法1 简单,但是不好用
     17 func InsertHeroNode(head *HeroNode, NewHeroNode *HeroNode) {
     18 
     19     /*创建临时变量t = 头部结点*/
     20     t := head
     21     for {
     22         /* 如果 临时变量t的下一个是nil,就表示到达的末尾,跳过 */
     23         if t.Next == nil {
     24             break
     25         }
     26         /* 将t的下一个结点给t,那么t会一直判断是否为nil,这样就更加确定,t就代表最后一个结点 */
     27         t = t.Next
     28     }
     29     /* 添加下一个结点 */
     30     t.Next = NewHeroNode
     31 
     32 }
     33 
     34 //InsertHeroNode2 插入英雄结点方法2 (根据编号大小排序插入数据)
     35 func InsertHeroNode2(head *HeroNode, NewHeroNode *HeroNode) {
     36 
     37     /*创建临时变量t = 头部结点*/
     38     t := head
     39     flag := true
     40     for {
     41         if t.Next == nil {
     42             break
     43         } else if t.Next.Nom > NewHeroNode.Nom {
     44             /* > 表示按照从小到大 < 表示 从大到小  >= <= 可根据需求更改*/
     45             break
     46         } else if t.Next.Nom == NewHeroNode.Nom {
     47             flag = false
     48             break
     49         }
     50         t = t.Next
     51     }
     52 
     53     /* 如果flag == true 表示可以存放 */
     54     if flag {
     55 
     56         /*
     57             顺序一定先将 新节点的下一个节点指向 → 头部的下一个节点,
     58             然后,再将头部的下一个节点指向 → 新节点,
     59             不然链表数据就断掉了
     60         */
     61 
     62         /*  ,将新节点的下一个结点指向 头部的下一个结点*/
     63         NewHeroNode.Next = t.Next
     64 
     65         /* 将新节点 指向 头部下一个结点 */
     66         t.Next = NewHeroNode
     67 
     68         fmt.Printf("添加节点 %v %v %v 成功
    ", NewHeroNode.Nom, NewHeroNode.Name, NewHeroNode.NickName)
     69 
     70         /* 如果 flag == false 不能存放*/
     71     } else {
     72         fmt.Printf("添加失败,结点编号 %v 已存在!
    ", NewHeroNode.Nom)
     73     }
     74 
     75 }
     76 
     77 //DelHeroNodeByID 根据ID删除节点
     78 func DelHeroNodeByID(head *HeroNode, id int) {
     79     t := head
     80     state := false
     81     for {
     82         if t.Next == nil {
     83             break
     84         } else if t.Next.Nom == id {
     85             /* 找到了ID */
     86             state = true
     87             break
     88         }
     89 
     90         /* 一直往后找 */
     91         t = t.Next
     92     }
     93 
     94     if state {
     95         /*
     96             找到了 删除,
     97             将头部的下一个节点 指向 头部的下一个的下一个节点,
     98             这样 头部的下一个节点就成垃圾了
     99 
    100         */
    101         t.Next = t.Next.Next
    102         fmt.Printf("节点 %v 已删除!
    ", id)
    103     } else {
    104         /* 未找到 */
    105         fmt.Printf("您输入的ID号 %v 未找到!
    ", id)
    106     }
    107 }
    108 
    109 //UpdateToNode 修改节点信息
    110 func UpdateToNode(head *HeroNode, id int, NewHeroNode *HeroNode) {
    111 
    112     /*创建临时变量t = 头部结点*/
    113     t := head
    114     flag := false
    115 
    116     for {
    117         if t.Next == nil {
    118             break
    119         } else if t.Next.Nom == id {
    120             flag = true
    121             break
    122         }
    123         t = t.Next
    124     }
    125     fmt.Println("修改节点前", t.Next)
    126     /* 如果flag == true 表示可以 修改 */
    127     if flag {
    128         t.Next.Nom = NewHeroNode.Nom
    129         t.Next.Name = NewHeroNode.Name
    130         t.Next.NickName = NewHeroNode.NickName
    131         fmt.Println("修改节点成功")
    132         fmt.Println("修改节点后", NewHeroNode)
    133         /* 如果 flag == false 不能存放*/
    134     } else {
    135         fmt.Printf("添加失败,结点编号 %v 已存在!
    ", NewHeroNode.Nom)
    136     }
    137 
    138 }
    139 
    140 //PrintListHeroInfo 输出链表hero信息
    141 func PrintListHeroInfo(head *HeroNode) {
    142 
    143     /*创建临时变量t = 头部结点*/
    144     t := head
    145 
    146     /* 判断是否为空 */
    147     if t.Next == nil {
    148         fmt.Println("链表为空...")
    149         return
    150     }
    151 
    152     /* 不为空时执行 */
    153     fmt.Println("链表数据:↓")
    154     for {
    155 
    156         fmt.Printf("%v %v %v	
    ", t.Next.Nom, t.Next.Name, t.Next.NickName)
    157 
    158         t = t.Next
    159 
    160         if t.Next == nil {
    161             break
    162         }
    163 
    164     }
    165     fmt.Println()
    166 }
    167 
    168 //CRUDToList 增删改查列表
    169 func CRUDToList(head *HeroNode) {
    170 
    171     for {
    172         var key int
    173         var id int
    174         var name string
    175         var nickeame string
    176         var NewNode *HeroNode
    177         fmt.Println("				用户信息链表操作系统")
    178         fmt.Println(
    179             `
    180                 1.        添加节点
    181                 2.        删除节点
    182                 3.        修改节点
    183                 4.        查看链表
    184                 5.        退出系统
    185                 请输入(1-5)进行操作
    186         `)
    187         fmt.Scanln(&key)
    188         switch key {
    189         case 1:
    190 
    191             fmt.Println("请输入新节点的 [ ID 英雄名称 英雄昵称 ], 以空格分隔输入!")
    192             fmt.Scanf("%v %v %v
    ", &id, &name, &nickeame)
    193             NewNode = &HeroNode{
    194                 Nom:      id,
    195                 Name:     name,
    196                 NickName: nickeame,
    197             }
    198 
    199             InsertHeroNode2(head, NewNode)
    200 
    201         case 2:
    202             fmt.Println("请输入删除节点ID")
    203             fmt.Scanln(&id)
    204             DelHeroNodeByID(head, id)
    205         case 3:
    206             fmt.Println(
    207                 `
    208                 请输入修改内容 [ id name nickname ] 以空格分隔输入
    209                 `)
    210             fmt.Scanf("%v %v %v
    ", &id, &name, &nickeame)
    211             NewNode = &HeroNode{
    212                 Nom:      id,
    213                 Name:     name,
    214                 NickName: nickeame,
    215             }
    216             UpdateToNode(head, id, NewNode)
    217         case 4:
    218             PrintListHeroInfo(head)
    219         case 5:
    220             fmt.Println("已退出系统...")
    221             os.Exit(0)
    222         default:
    223             fmt.Println("操作有误,请输入(1-4)数字!")
    224         }
    225     }
    226 }
    227 
    228 func main() {
    229 
    230     //Hero 链表 头结点HeroListLinkHead
    231     head := &HeroNode{}
    232 
    233     CRUDToList(head)
    234 }
    单向链表
    • 双向链表

      1 package main
      2 
      3 import (
      4     "fmt"
      5     "os"
      6 )
      7 
      8 /*
      9 HeroNode 英雄结构体
     10 
     11 Nom 编号
     12 
     13 Name  名称
     14 
     15 NickName 昵称
     16 
     17 Next 指向下一个节点
     18 
     19 Last 指向上一个节点
     20 
     21 */
     22 type HeroNode struct {
     23     Nom      int
     24     Name     string
     25     NickName string
     26     Next     *HeroNode
     27     Last     *HeroNode
     28 }
     29 
     30 //InsertHeroNode 双向链表插入新节点 (根据编号大小排序插入数据)
     31 func InsertHeroNode(head *HeroNode, NewHeroNode *HeroNode) {
     32 
     33     /*创建临时变量t = 头部结点*/
     34     t := head
     35     flag := true
     36     for {
     37         if t.Next == nil {
     38             break
     39         } else if t.Next.Nom > NewHeroNode.Nom {
     40             /* > 表示按照从小到大 < 表示 从大到小  >= <= 可根据需求更改*/
     41             break
     42         } else if t.Next.Nom == NewHeroNode.Nom {
     43             flag = false
     44             break
     45         }
     46         t = t.Next
     47     }
     48 
     49     /* 如果flag == true 表示可以存放 */
     50     if flag {
     51 
     52         /* 将 新节点的下一个节点指向 头部节点原先指向的 下一个结点*/
     53         NewHeroNode.Next = t.Next
     54 
     55         /* 将 新节点的上一个节点 指向 t头部节点 */
     56         NewHeroNode.Last = t
     57 
     58         /* 将 头节点的下一个节点的上一个节点不为空时才指向新节点,不然会发生空指针引用 */
     59         if t.Next.Last != nil {
     60             /* 将头节点原先指向的下一个节点的上一个节点 指向 新节点 */
     61             t.Next.Last = NewHeroNode
     62         }
     63 
     64         /* 将 头部节点的下一个节点 指向 新节点 */
     65         t.Next = NewHeroNode
     66 
     67         fmt.Printf("添加节点 %v %v %v 成功
    ", NewHeroNode.Nom, NewHeroNode.Name, NewHeroNode.NickName)
     68 
     69         /* 如果 flag == false 不能存放*/
     70     } else {
     71         fmt.Printf("添加失败,结点编号 %v 已存在!
    ", NewHeroNode.Nom)
     72     }
     73 
     74 }
     75 
     76 //DelHeroNodeByID 根据ID删除节点
     77 func DelHeroNodeByID(head *HeroNode, id int) {
     78     t := head
     79     state := false
     80     for {
     81         if t.Next == nil {
     82             break
     83         } else if t.Next.Nom == id {
     84             /* 找到了ID */
     85             state = true
     86             break
     87         }
     88 
     89         /* 一直往后找 */
     90         t = t.Next
     91     }
     92 
     93     if state {
     94         /*
     95             找到了 删除,
     96             将头部的下一个节点 指向 头部的下一个的下一个节点,
     97             这样 头部的下一个节点就成垃圾了
     98 
     99         */
    100         t.Next = t.Next.Next
    101         if t.Next != nil {
    102             t.Next.Last = t
    103             fmt.Printf("节点 %v 已删除!
    ", id)
    104         }
    105 
    106     } else {
    107         /* 未找到 */
    108         fmt.Printf("您输入的ID号 %v 未找到!
    ", id)
    109     }
    110 }
    111 
    112 //UpdateToNode 修改节点信息
    113 func UpdateToNode(head *HeroNode, id int, NewHeroNode *HeroNode) {
    114 
    115     /*创建临时变量t = 头部结点*/
    116     t := head
    117     flag := false
    118 
    119     for {
    120         if t.Next == nil {
    121             break
    122         } else if t.Next.Nom == id {
    123             flag = true
    124             break
    125         }
    126         t = t.Next
    127     }
    128     fmt.Println("修改节点前", t.Next)
    129     /* 如果flag == true 表示可以 修改 */
    130     if flag {
    131         t.Next.Nom = NewHeroNode.Nom
    132         t.Next.Name = NewHeroNode.Name
    133         t.Next.NickName = NewHeroNode.NickName
    134 
    135         fmt.Println("修改节点成功")
    136         fmt.Println("修改节点后", NewHeroNode)
    137 
    138         /* 如果 flag == false 不能存放*/
    139     } else {
    140         fmt.Printf("添加失败,结点编号 %v 已存在!
    ", NewHeroNode.Nom)
    141     }
    142 
    143 }
    144 
    145 //PrintListHeroInfo 正向输出链表hero信息
    146 func PrintListHeroInfo(head *HeroNode) {
    147 
    148     /*创建临时变量t = 头部结点*/
    149     t := head
    150 
    151     /* 判断是否为空 */
    152     if t.Next == nil {
    153         fmt.Println("链表为空...")
    154         return
    155     }
    156 
    157     /* 不为空时执行 */
    158     fmt.Println("链表数据:↓")
    159     for {
    160 
    161         fmt.Printf("%v %v %v	
    ", t.Next.Nom, t.Next.Name, t.Next.NickName)
    162 
    163         t = t.Next
    164 
    165         if t.Next == nil {
    166             break
    167         }
    168 
    169     }
    170     fmt.Println()
    171 }
    172 
    173 //PrintListHeroInfoByReverse 你想输出链表信息
    174 func PrintListHeroInfoByReverse(head *HeroNode) {
    175     t := head
    176     if t.Next == nil {
    177         fmt.Println("空链表...")
    178         return
    179     }
    180     /* 让t 定位到链表末尾 */
    181     for {
    182         if t.Next == nil {
    183             break
    184         }
    185         t = t.Next
    186     }
    187 
    188     /* 反向遍历 */
    189     for {
    190         fmt.Printf("%v %v %v	
    ", t.Nom, t.Name, t.NickName)
    191         t = t.Last
    192         if t.Last == nil {
    193             break
    194         }
    195     }
    196 }
    197 
    198 //CRUDToList 增删改查列表
    199 func CRUDToList(head *HeroNode) {
    200 
    201     for {
    202         var key int
    203         var id int
    204         var name string
    205         var nickeame string
    206         var NewNode *HeroNode
    207         fmt.Println("				用户信息链表操作系统")
    208         fmt.Println(
    209             `
    210                 1.        添加节点
    211                 2.        删除节点
    212                 3.        修改节点
    213                 4.        查看链表
    214                 5.        退出系统
    215                 请输入(1-5)进行操作
    216         `)
    217         fmt.Scanln(&key)
    218         switch key {
    219         case 1:
    220 
    221             fmt.Println("请输入新节点的 [ ID 英雄名称 英雄昵称 ], 以空格分隔输入!")
    222             fmt.Scanf("%v %v %v
    ", &id, &name, &nickeame)
    223             /* 限制输入 id不能为0  名称不能为空 昵称不能为空,否则不添加 */
    224 
    225             if name != " " && nickeame != " " {
    226                 if id == 0 {
    227                     break
    228                 }
    229                 NewNode = &HeroNode{
    230                     Nom:      id,
    231                     Name:     name,
    232                     NickName: nickeame,
    233                 }
    234 
    235                 InsertHeroNode(head, NewNode)
    236                 fmt.Println("节点添加成功")
    237             } else {
    238                 fmt.Println("节点添加失败...")
    239             }
    240 
    241         case 2:
    242             fmt.Println("请输入删除节点ID")
    243             fmt.Scanln(&id)
    244             DelHeroNodeByID(head, id)
    245         case 3:
    246             fmt.Println(
    247                 `
    248                 请输入修改内容 [ id name nickname ] 以空格分隔输入
    249                 `)
    250             fmt.Scanf("%v %v %v
    ", &id, &name, &nickeame)
    251             NewNode = &HeroNode{
    252                 Nom:      id,
    253                 Name:     name,
    254                 NickName: nickeame,
    255             }
    256             UpdateToNode(head, id, NewNode)
    257         case 4:
    258             fmt.Println(
    259                 `
    260             请问要看 哪个方向的输出格式的链表?
    261             1.        正向输出 
    262             2.        逆向输出`)
    263             fmt.Scanln(&key)
    264             switch key {
    265             case 1:
    266                 PrintListHeroInfo(head)
    267             case 2:
    268                 PrintListHeroInfoByReverse(head)
    269             default:
    270                 fmt.Println("输入查看链表的方式有误!")
    271             }
    272         case 5:
    273             fmt.Println("已退出系统...")
    274             os.Exit(0)
    275         default:
    276             fmt.Println("操作有误,请输入(1-4)数字!")
    277         }
    278     }
    279 }
    280 
    281 func main() {
    282 
    283     //Hero 链表 头结点HeroListLinkHead
    284     head := &HeroNode{}
    285 
    286     CRUDToList(head)
    287 }
    双向链表
    • 单向环形链表(约瑟夫问题(丢手绢))

    •   1 package main
        2 
        3 import "fmt"
        4 
        5 //Child 孩子结构体
        6 type Child struct {
        7     no   int
        8     next *Child
        9 }
       10 
       11 //AddChild 添加孩子
       12 func AddChild(num int) *Child {
       13     first := &Child{}
       14     currentChild := &Child{}
       15     if num < 1 {
       16         fmt.Println("num值太少了,不够玩的")
       17         return first
       18     }
       19     for i := 1; i <= num; i++ {
       20         child := &Child{
       21             no: i,
       22         }
       23         if i == 1 {
       24             first = child
       25             currentChild = child
       26             currentChild.next = first
       27         } else {
       28             currentChild.next = child
       29             currentChild = child
       30             currentChild.next = first
       31         }
       32     }
       33     return first
       34 }
       35 
       36 //PrintChild 输出孩子链表
       37 func PrintChild(first *Child) {
       38     if first.next == nil {
       39         fmt.Println("链表为空,没有孩子")
       40         return
       41     }
       42 
       43     currentChild := first
       44     for {
       45         fmt.Printf("孩子编号:%v 
      ", currentChild.no)
       46         if currentChild.next == first {
       47             break
       48         }
       49         currentChild = currentChild.next
       50     }
       51 }
       52 
       53 /*
       54 ThrowTheHandkerchief 丢手绢
       55 
       56 first *Child    第一个孩子的节点
       57 
       58 startNum int    开始从第几个孩子数
       59 
       60 countNum int    数几下
       61 */
       62 func ThrowTheHandkerchief(first *Child, startNum int, countNum int) {
       63     if first.next == nil {
       64         fmt.Println("空链表,请添加孩子")
       65         return
       66     }
       67 
       68     tail := first
       69     for {
       70         if tail.next == first {
       71             break
       72         }
       73         tail = tail.next
       74     }
       75 
       76     for i := 1; i <= startNum-1; i++ {
       77         first = first.next
       78         tail = tail.next
       79     }
       80 
       81     for {
       82         for i := 1; i <= countNum-1; i++ {
       83             first = first.next
       84             tail = tail.next
       85         }
       86         fmt.Printf("编号为 %v 的孩子出圈了
      ", first.no)
       87         first = first.next
       88         tail.next = first
       89         if tail == first {
       90             break
       91         }
       92     }
       93     fmt.Printf("编号为 %v 的孩子最后出圈...
      ", first.no)
       94 
       95 }
       96 func main() {
       97     firstChild := AddChild(100)
       98     PrintChild(firstChild)
       99     ThrowTheHandkerchief(firstChild, 99, 25)
      100 }
      单向环形链表
    时间若流水,恍惚间逝去
  • 相关阅读:
    debug和release转载
    坐标系与基本图元(8)
    坐标系与基本图元(7)
    坐标系与基本图元(5)
    坐标系与基本图元(6)
    坐标系与基本图元(4)
    坐标系与基本图元(3)
    坐标系与基本图元(2)
    BZOJ 1090
    Xor
  • 原文地址:https://www.cnblogs.com/alanshreck/p/14170680.html
Copyright © 2020-2023  润新知