• 单向链表实现及增删改查
  • 双向链表实现及增删改查
  • 循环链表实现及增删改查

链表是一个有序(FIFO)的列表

单链表

带头节点的单向链表
头节点的作用: 不存放数据,用来标识链表头,为了方便的对单链表进行增删改查

单链表实现

next指向下一个节点

type heroNode struct {
	number   int
	name     string
	nickname string
	next *heroNode
}

给单链表新增节点

直接在链表尾部插入
思路: 判断当前节点是否为最后一个节点,如果是则插入,不是则遍历下个节点

func insert(head *heroNode, newHeroNode *heroNode) {
	for {
		// 如果 true 表示找到链表末尾; 并赋值插入
		if head.next == nil {
			head.next = newHeroNode
			return
		} else {
			// 当前node不是,则进入下一个node
			head = head.next
        }
        
	}

}

根据编号从小到大排列插入指定位置
前提: 节点已是从小到大排列顺序
思路: 带插入节点newHeroNode.number编号小于head.next.number则找到位置

func insertById(head *heroNode, newHeroNode *heroNode) {
	for {
		// 如果 true 表示找到链表末尾; 并赋值
		if head.next == nil {
			head.next = newHeroNode
			return
		} else if newHeroNode.number < head.next.number {
			newHeroNode.next = head.next
			head.next = newHeroNode
			return
		} else if newHeroNode.number == head.next.number {
			fmt.Println("存在相同id,不允许插入")
			return
		} else {
			// 当前node不是,则进入下一个node
			head = head.next
		}

	}

}

删除单链表中指定节点

思路: 当前所在节点在待删除节点前一位,将当前节点的next直接指向待删除节点中的next(取代待删除节点)

func deleteById(head *heroNode, number int) {
	for {
		// 没找到符合指定条件的节点
		if head.next == nil {
			fmt.Println("不存在de序号: ", number)
			return
		} else if number == head.next.number {
			// 实现
			if head.next.next != nil {
				head.next = head.next.next
			} else {
				head.next = nil
			}
			return
		} else {
			// 当前node不是,则进入下一个node
			head = head.next
		}

	}

}

更新单链表中指定节点

func update(head *heroNode, newHeroNode *heroNode) {
	for {
		// 没找到
		if head.next == nil {
			fmt.Println("不存在de序号: ", newHeroNode.number)
			return
		} else if newHeroNode.number == head.next.number {
			// 实现更新
			newHeroNode.next = head.next.next
			head.next = newHeroNode
			return
		} else {
			head = head.next
		}

	}

}

查询单链表中所有节点信息

func listHeroNode(head *heroNode) {
	for {
		// 1. 判断当前 node 是否为末尾 node ( 当前 node 的 next 的值是否是空指针 nil)
		if head.next == nil {
			return
		}

		// 2. 不是则输出 info
		fmt.Printf("排名: %d \t 姓名: %s \t 昵称: %s \n", head.next.number, head.next.name, head.next.nickname)

		// 3. "移至"下一个节点
		head = head.next
	}

}

测试

func main() {
	// 1. 先创建一个头节点,
	head := &heroNode{}

	// 2. 创建一个新的heroNode
	hero1 := &heroNode{
		number:   1,
		name:     "宋江",
		nickname: "及时雨",
	}

	hero2 := &heroNode{
		number:   2,
		name:     "林冲",
		nickname: "豹子头",
	}

	hero3 := &heroNode{
		number:   3,
		name:     "卢俊义",
		nickname: "玉麒麟",
	}

	hero4 := &heroNode{
		number:   4,
		name:     "吴用",
		nickname: "智多星",
	}

	// 3. 增
	insertById(head, hero3)
	insertById(head, hero1)
	insertById(head, hero2)
	insertById(head, hero4)
	// insertById(head, hero4)

	// 4. 查
	listHeroNode(head)

	// 5. 删
	deleteById(head, 4)

	// 6. 改
	heroUpdate := &heroNode{
		number:   2,
		name:     "林不冲",
		nickname: "狮子头",
	}
	update(head, heroUpdate)

	// 4. 查
	fmt.Println()
	listHeroNode(head)
}

运行结果如下: 2020-3-22-0-47-32.png

双向链表

带头节点的双向链表

双向链表实现

pre 指向前一个节点 next 指向下一个节点

type heroNode struct {
	number   int
	name     string
	nickname string
	pre      *heroNode
	next     *heroNode
}

给双链表新增节点

直接在双向链表尾部插入
思路: 找到链表的最后一个节点, 描述 head.next 和 newHeroNode.pre

func insert(head *heroNode, newHeroNode *heroNode) {

	for {
		// 如果 true 表示找到链表末尾; 并赋值
		if head.next == nil {
			head.next = newHeroNode
			newHeroNode.pre = head
			return
		} else {
			// 当前node不是,则进入下一个node
			head = head.next
		}

	}

}

根据编号从小到大排列插入指定位置 前提: 节点已是从小到大排列顺序 思路: head.next.number > newHeroNode.number

func insertById(head *heroNode, newHeroNode *heroNode) {

	for {
		// 如果 true 表示找到链表末尾;
		if head.next == nil {
			head.next = newHeroNode
			newHeroNode.pre = head
			return
		} else if newHeroNode.number <= head.next.number {
			head.next.pre = newHeroNode
			newHeroNode.next = head.next
			newHeroNode.pre = head
			head.next = newHeroNode
			return
		} else if newHeroNode.number == head.next.number {
			fmt.Println("存在相同id,不允许插入")
			return
		} else {
			// 当前node不是,则进入下一个node
			head = head.next
		}

	}

}

删除双链表中指定节点

思路:

当前所在节点在待删除节点前一位

  1. 将待删除节点的下一个节点的pre指向当前节点
  2. 将当前节点 head.next 指向待删除节点的下一个节点,即 head.next.next
func deleteById(head *heroNode, number int) {
	for {
		// 没找到
		if head.next == nil {
			fmt.Println("不存在de序号: ", number)
			return
		} else if number == head.next.number {
			// 实现
			if head.next.next != nil {
				head.next.next.pre = head
				head.next = head.next.next
			} else {
				head.next = nil
			}
			return
		} else {
			// 当前node不是,则进入下一个node
			head = head.next
		}

	}

}

更新双链表中指定节点

思路: 找到符合条件的节点 newHeroNode.number == head.next.number

func update(head *heroNode, newHeroNode *heroNode) {
	for {
		// 没找到
		if head.next == nil {
			fmt.Println("不存在de序号: ", newHeroNode.number)
			return
		} else if newHeroNode.number == head.next.number {
			// 实现4步关联
			// 修改待更新节点的下个节点的pre
			head.next.next.pre = newHeroNode
			// 更新节点
			newHeroNode.pre = head
			newHeroNode.next = head.next.next
			// 修改当前节点的next
			head.next = newHeroNode
			return
		} else {
			head = head.next
		}

	}

}

查询双链表中所有节点信息

func listHeroNode(head *heroNode) {
	for {
		// 1. 判断当前 node 是否为末尾 node ( 当前 node 的 next 的值是否是空指针 nil)
		if head.next == nil {
			return
		}

		// 2. 不是则输出 info
		fmt.Printf("prev排名: %d \t 姓名: %s \t 昵称: %s \n", head.number, head.name, head.nickname)
		fmt.Printf("curr排名: %d \t 姓名: %s \t 昵称: %s \n", head.next.number, head.next.name, head.next.nickname)
		if head.next.next != nil {
			fmt.Printf("next排名: %d \t 姓名: %s \t 昵称: %s \n", head.next.next.number, head.next.next.name, head.next.next.nickname)
		}
		fmt.Println("---------")

		// 3. 将当前node下的next传给head
		head = head.next
	}

}

main函数

func main() {
	// 1. 先创建一个头节点,
	head := &heroNode{}

	// 2. 创建一个新的heroNode
	hero1 := &heroNode{
		number:   1,
		name:     "宋江",
		nickname: "及时雨",
	}

	hero2 := &heroNode{
		number:   2,
		name:     "林冲",
		nickname: "豹子头",
	}

	hero3 := &heroNode{
		number:   3,
		name:     "卢俊义",
		nickname: "玉麒麟",
	}

	hero4 := &heroNode{
		number:   4,
		name:     "吴用",
		nickname: "智多星",
	}

	// 3. 在尾部新增节点
	insert(head, hero1)
	// insert(head, hero2)
	insert(head, hero3)
	insert(head, hero4)

	// 3.1 指定位置新增节点
	listHeroNode(head)
	insertById(head, hero2)

	// 4. 查
	listHeroNode(head)

	// 删
	fmt.Println("删除操作")
	deleteById(head, 3)
	listHeroNode(head)

	// 改
	fmt.Println("更新操作")
	// 6. 改
	heroUpdate := &heroNode{
		number:   2,
		name:     "林不冲",
		nickname: "狮子头",
	}
	update(head, heroUpdate)
	listHeroNode(head)

}

循环链表

无头无尾,首节点和末节点连接在一起

循环链表实现

给循环链表新增节点

删除循环链表中指定节点

更新循环链表中指定节点

查询循环链表中所有节点信息