定义
linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说的链表,结构有单向链表、双向链表和环形链表。
特点
查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素
增删元素快:添加或者删除某个元素,只要更换上一个节点和下一个节点就可以了
应用场景
- 结合哈希表:LRU 缓存、链地址法解决哈希冲突。
- 循环链表:约瑟夫问题
单向链表
基本结构和操作
//
// LinkNode
// @Description: 链表节点
//
type LinkNode struct {
value string
next *LinkNode
}
添加节点
//
// AddNode
// @Description: 添加节点
// @Author: maxwell.ke
// @time 2022-10-26 13:59:34
// @receiver ln
// @param n
// @return error
//
func (ln *LinkNode) AddNode(addNode *LinkNode) error {
tail := ln
for {
if tail.next == nil {
//找到了最后一个结点
break
}
//如果没有找到,把当前结点的next指向临时结点
tail = tail.next
}
tail.next = addNode
return nil
}
删除节点
//
// DelNode
// @Description: 移除节点
// @Author: maxwell.ke
// @time 2022-10-26 14:07:13
// @receiver ln
// @param delNode
// @return error
//
func (ln *LinkNode) DelNode(delNode *LinkNode) error {
tail := ln
for {
//找到比需要删除的节点的前一个节点
if delNode == tail { //删除的是头节点,不可删除
return fmt.Errorf("头节点不可删除")
}
if tail.next == nil {
return fmt.Errorf("没有找到需要删除的节点")
}
if tail.next == delNode {
break
}
//如果没有找到,把当前结点的next指向临时结点
tail = tail.next
}
//开始删除
tail.next = delNode.next
return nil
}
遍历链表
//
// ShowLink
// @Description: 遍历链表
// @Author: maxwell.ke
// @time 2022-10-26 14:30:51
// @receiver ln
//
func (ln *LinkNode) ShowLink() {
tail := ln
for {
if tail == nil {
break
}
fmt.Printf("[%s]->", tail.value)
tail = tail.next
}
fmt.Println()
}
双向链表
基本结构和操作
type HeroNode struct {
val string
pre *HeroNode
next *HeroNode
}
添加节点
//
// AddNode
// @Description: 添加节点
// @Author: maxwell.ke
// @time 2022-10-26 14:47:52
// @receiver ln
// @param node
//
func (ln *LinkNode) AddNode(node *LinkNode) {
tail := ln
for {
if tail.next == nil {
//找到了最后一个结点
break
}
//如果没有找到,把当前结点的next指向临时结点
tail = tail.next
}
tail.next = node
node.pre = tail
}
删除节点
//
// DelNode
// @Description: 删除节点
// @Author: maxwell.ke
// @time 2022-10-26 14:51:27
// @receiver ln
// @param delNode
// @return error
//
func (ln *LinkNode) DelNode(delNode *LinkNode) error {
tail := ln
for {
//找到比需要删除的节点的前一个节点
if delNode == ln {
return fmt.Errorf("头结点不可删除")
}
if tail.next == nil {
return fmt.Errorf("没有找到需要删除的节点")
}
if tail.next == delNode {
break
}
//如果没有找到,把当前结点的next指向临时结点
tail = tail.next
}
//开始删除
tail.next = delNode.next
delNode.next.pre = tail
return nil
}
遍历链表
//
// ShowLink
// @Description: 遍历链表
// @Author: maxwell.ke
// @time 2022-10-26 14:54:17
// @receiver ln
//
func (ln *LinkNode) ShowLink() {
tail := ln
if tail.next == nil {
fmt.Println("空链表")
return
}
for {
fmt.Printf("[%s]->", tail.next.value)
tail = tail.next
if tail.next == nil {
break
}
}
fmt.Println()
}
环形链表
环形单向链表
//
// LinkNode
// @Description: 链表节点
//
type LinkNode struct {
value string
next *LinkNode
}
添加节点
func (ln *LinkNode) AddNode(newNode *LinkNode) {
//头节点,直接加
if ln.next == nil {
ln.value = newNode.value
ln.next = ln
return
}
tail := ln
for {
if tail.next == ln {
break
}
tail = tail.next
}
//加入链表
tail.next = newNode
newNode.next = ln
}
删除节点
//
// DelNode
// @Description: 删除节点
// @Author: maxwell.ke
// @time 2022-10-26 15:51:54
// @receiver ln
// @param delNode
// @return newLink
// @return err
//
func (ln *LinkNode) DelNode(delNode *LinkNode) (newLink *LinkNode, err error) {
//空链表
if ln.next == nil {
return nil, fmt.Errorf("链表为空")
}
//1个元素的链表
if ln.next == ln {
if ln == delNode {
return nil, nil
} else {
return nil, fmt.Errorf("未找到要删除的节点")
}
}
//多个元素的链表
tailNode := ln //头节点
rearNode := ln //尾节点
//找到尾结点
for {
if rearNode.next == ln {
break
}
rearNode = rearNode.next
}
for {
//头节点就是需要删除的节点
if tailNode == delNode {
newLink = tailNode.next
rearNode.next = newLink
break
}
//中间节点是需要删除的节点
if tailNode.next == delNode {
tailNode.next = delNode.next
break
}
//尾节点是需要删除的节点
if tailNode.next == ln {
if tailNode == delNode {
//找到倒数第二个节点
descSecondNode := ln
for {
if descSecondNode.next == tailNode {
break
}
descSecondNode = descSecondNode.next
}
descSecondNode.next = ln
} else {
return nil, fmt.Errorf("未找到要删除的节点")
}
break
}
tailNode = tailNode.next
}
return
}
遍历链表
//
// showLink
// @Description: 遍历链表
// @Author: maxwell.ke
// @time 2022-10-26 15:54:18
// @receiver ln
//
func (ln *LinkNode) showLink() {
tail := ln
if tail.next == nil {
fmt.Println("链表为空")
return
}
for {
fmt.Printf("%s-->", tail.value)
if tail.next == ln {
break
}
tail = tail.next
}
fmt.Println()
}
案例:约瑟夫问题
设编号为1,2…n个人围成一圈,约定编号为K(1 <= k <= n)的人从1开始报数,数到m的那个人
出列,它的下一位又从1开始报数,数到m的那个人又出列,以此类推,直到所有人出列为止,由此产生
一个出列编号的序列。
package main
import "fmt"
type joshefu struct {
no int
next *joshefu
}
/**
* @Description: 创建一个链表
* @Param:num:链表的长度
* @Return:返回环形链表的头结点
*/
func addLink(num int) *joshefu {
if num <= 0 {
return nil
}
head := &joshefu{}
p := head
for i := 1; i <= num; i++ {
p.no = i
if i == num {
p.next = head
} else {
p.next = &joshefu{}
}
p = p.next
}
return head
}
func showLink(head *joshefu) {
p := head
for {
if p.next == nil {
fmt.Println("链表为空")
break
}
fmt.Printf("%d -->", p.no)
if p.next == head {
break
}
p = p.next
}
fmt.Println()
}
func delLink(head *joshefu, start int, step int) {
if head.next == nil {
fmt.Println("链表为空")
return
}
//寻找尾节点
rearNode := head
for {
if rearNode.next == head {
break
}
rearNode = rearNode.next
}
//让head移动到start节点(start-1)
for i := 1; i <= start-1; i++ {
head = head.next
rearNode = rearNode.next
}
//创建一个数组
var delArr []int
fmt.Println(head.no)
//找到删除节点并删除
for {
for j := 1; j <= step-1; j++ {
head = head.next
rearNode = rearNode.next
}
delArr = append(delArr, head.no)
head = head.next
rearNode.next = head
if head == rearNode {
delArr = append(delArr, head.no)
break
}
}
//展示出列顺序
fmt.Println(delArr)
}
func main() {
linkHead := addLink(10)
showLink(linkHead)
delLink(linkHead, 3, 4)
}