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 成功\n", NewHeroNode.Nom, NewHeroNode.Name, NewHeroNode.NickName)
 69 
 70         /* 如果 flag == false 不能存放*/
 71     } else {
 72         fmt.Printf("添加失败,结点编号 %v 已存在!\n", 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 已删除!\n", id)
103     } else {
104         /* 未找到 */
105         fmt.Printf("您输入的ID号 %v 未找到!\n", 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 已存在!\n", 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\n", 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("\t\t\t\t用户信息链表操作系统")
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\n", &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\n", &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 成功\n", NewHeroNode.Nom, NewHeroNode.Name, NewHeroNode.NickName)
 68 
 69         /* 如果 flag == false 不能存放*/
 70     } else {
 71         fmt.Printf("添加失败,结点编号 %v 已存在!\n", 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 已删除!\n", id)
104         }
105 
106     } else {
107         /* 未找到 */
108         fmt.Printf("您输入的ID号 %v 未找到!\n", 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 已存在!\n", 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\n", 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\n", 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("\t\t\t\t用户信息链表操作系统")
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\n", &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\n", &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 \n", 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 的孩子出圈了\n", first.no)
     87         first = first.next
     88         tail.next = first
     89         if tail == first {
     90             break
     91         }
     92     }
     93     fmt.Printf("编号为 %v 的孩子最后出圈...\n", first.no)
     94 
     95 }
     96 func main() {
     97     firstChild := AddChild(100)
     98     PrintChild(firstChild)
     99     ThrowTheHandkerchief(firstChild, 99, 25)
    100 }
    单向环形链表

     

posted @ 2020-12-21 23:05  伊凡晴天  阅读(179)  评论(0编辑  收藏  举报