链表

链表

单向链表

定义一个HeroNode

// 定义一个HeroNode
type HeroNode1 struct{
	no int
	name string
	nickname string
	next *HeroNode
}

给链表添加一个节点

  • 方式一:直接在链表最后加入
func InsertHeroNode1(head, newHeroNode *HeroNode){
	// 1.先找到该链表的最后节点
	// 2.创建一个辅助节点
	temp := head
	for {
		if temp.next == nil {
			// 表示已经找到最后
			break
		}
		temp = temp.next // 让temp不断指向下一个节点
	}
	// 3.将newHeroNode 加入到链表的最后
	temp.next = newHeroNode
}
  • 方式二:根据no的编号从小到大插入
func InsertHeroNode2(head, newHeroNode *HeroNode){
	// 1.找到适当的节点
	// 2.创建辅助节点
	temp := head
	// 让插入的节点no,和temp的下一个节点的no比较
	for{
		if temp.next == nil {
			// 说明到链表的最后
			break
		}else if temp.next.no >= newHeroNode.no{
			// 说明newHeroNode 就应该插入到temp后面
			break
		}
		temp = temp.next
	}
	newHeroNode.next = temp.next
	temp.next = newHeroNode
}

显示链表所有节点

func ListHeroNode1(head *HeroNode){
	//1.创建辅助节点
	temp := head
	// 先判断该链表是不是一个空链表
	if temp.next == nil {
		fmt.Println("空空如也。。。")
		return
	}
	// 2.遍历整个链表
	for {
		fmt.Printf("[%d,%s,%s]==>",temp.next.no,temp.next.name,temp.next.nickname)
		temp = temp.next
		if temp.next == nil {
			break
		}
	}
}

删除一个节点

// 删除一个节点
func DelHeroNode1(head *HeroNode, id int){
	temp := head
	for{
		if temp.next == nil {
			// 说明已经到链表的最后了
			break
		}else if temp.next.no == id {
			// 说明找到了需要删除的节点
			temp.next = temp.next.next
			return
		}
		temp = temp.next
	}
}

双向链表

定义一个HeroNode

type HeroNode struct{
	no int
	name string
	nickname string
	pre *HeroNode  // 这个表示指向前一个节点
	next *HeroNode  // 这个表示指向下一个节点
}

给链表添加一个节点

  • 方式一: 在双向链表最后加入
// 方式一:在双链表最后加入
func InsertHeroNode(head,newHeroNode *HeroNode){
	// 先找到该链表的最后节点
	// 创建一个辅助节点
	temp := head
	for {
		if temp.next == nil {
			// 表示找到最后
			break
		}
		temp = temp.next  // 让temp不断的指向下一个节点
	}
	// 将newHeroNode加入到链表的最后
	temp.next = newHeroNode
	newHeroNode.pre = temp
}
  • 方式二: 在双向链表指定位置加入
func InsertHeroNode2(head, newHeroNode *HeroNode){
	temp := head
	for{
		// 判断链表是否已经到最后了
		if temp.next == nil {
			break
		}else if temp.next.no >= newHeroNode.no{
			// 说明就应该插入到temp后面
			break
		}
		temp = temp.next
	}

	newHeroNode.next = temp.next  // 找到自己后面的,正向连接
	newHeroNode.pre = temp    // 找到自己前面的,反向连接
	if temp.next != nil {
		temp.next.pre = newHeroNode  // 自己后面的节点与自己反向连接
	}
	temp.next = newHeroNode   // 自己前面的和自己正向连接
}

显示双向链表

  • 正序显示
// 显示链表所有的节点信息
func ListHeroNode11(head *HeroNode){
	temp := head
	if temp.next == nil {
		fmt.Println("空空如也")
		return
	}
	// 遍历整个链表
	for {
		fmt.Printf("[%d,%s,%s]==>",temp.next.no,temp.next.name,temp.next.nickname)
		temp = temp.next
		if temp.next == nil {
			// 表明已经到链表结尾了
			return
		}
	}
}
  • 倒序显示
// 倒序显示双向链表所有信息
func ListHeroNode22(head *HeroNode){
	temp := head
	// 先判断该链表是不是一个空链表
	if temp.next == nil {
		fmt.Println("空空如也。。。")
		return
	}
	// 让temp定位到双向链表的最后节点
	for {
		if temp.next == nil {
			break
		}
		temp = temp.next
	}

	// 遍历这个链表
	for {
		fmt.Printf("[%d,%s,%s]==>",temp.no,temp.name,temp.nickname)
		// 判断是否链表表头
		temp = temp.pre
		if temp.pre == nil {
			break
		}
	}
}

删除指定节点

// 删除指定节点
func DelHeroNode(head *HeroNode, id int){
	temp := head
	for{
		if temp.next == nil {
			// 说明到链表最后了
			return
		}else if temp.next.no == id {
			temp.next = temp.next.next
			if temp.next != nil {
				temp.next.pre = temp
			}
		}
		temp = temp.next
	}
}

环形单向链表

定义HeroNode

type HeroNode struct{
	no int
	name string
	nickname string
	next *HeroNode
}

插入一个节点

func InsertHeroNode(head, newHeroNode *HeroNode){
	// 判断是不是添加第一个英雄
	if head.next == nil {
		head.no = newHeroNode.no
		head.name = newHeroNode.name
		head.nickname = newHeroNode.nickname
		head.next = head   // 构成一个环路
		return
	}

	// 定义一个临时变量,帮忙找到环形的最后节点
	temp := head
	for {
		if temp.next == head {
			break
		}
		temp = temp.next
	}
	// 加入环形链表中
	temp.next = newHeroNode
	newHeroNode.next = head
}

显示环形链表

func ListCircleLink(head *HeroNode){
	// 定义临时变量
	temp := head
	if temp.next == nil {
		fmt.Println("空空如也的环形链表")
		return
	}
	for{
		fmt.Printf("[%d,%s,%s]",temp.no,temp.name,temp.nickname)
		if temp.next == head {
			break
		}
		temp = temp.next
	}
}

删除一个节点

func DelHeroNode(head *HeroNode, id int)*HeroNode{
	temp := head
	helper := head
	// 空链表
	if temp.next == nil {
		fmt.Println("这是一个空的环形链表")
		return head
	}

	// 如果只有一个节点
	if temp.next == head {
		// 只有一个节点
		if temp.no == id{
			temp.next = nil
		}
		return head
	}

	// 将helper定位到链表最后
	for {
		if helper.next == head {
			break
		}
		helper = helper.next
	}
	flag := true
	for {
		if temp.next == head {
			// 如果到这里,说明比较到了最后一个节点[不包含最后一个]
			break
		}
		if temp.no == id {
			if temp == head {
				// 说明删除的节点是头节点
				head = head.next
			}
			helper.next = temp.next
			flag = false
			break
		}
		temp = temp.next
		helper = helper.next
	}
	if flag{
		if temp.no == id{
			helper.next = temp.next
		}
	}
	return head
}

环形单向链表应用实例

  • Josephu问题

Josephu问题为:设编号为1,2,... n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m那个人又出列,依次类推,直到所有人都出列为止,由此产生一个出队编号的序列。

提示

用一个不带头节点的循环链表来处理Josephu问题:先构成一个有n个节点的单循环链表,然后由k节点起从1开始计数,计到m时,对应节点从链表中删除,然后再从被删除节点的下一个节点又从1开始计数,直到最后一个节点从链表删除,算法结束。

type Boy struct{
	No int  // 编号
	Next *Boy  // 指向下一个小孩的指针【默认值是nil】
}

// 编写一个函数,构成单向环形链表
// num:表示小孩的个数
// *Boy:返回该环形链表的第一个小孩的指针
func AddBoy(num int)*Boy{
	first := &Boy{}  // 空节点
	temp := &Boy{}  // 空节点

	if num < 1{
		fmt.Println("num的值不对")
		return first
	}

	// 循环构建这个环形链表
	for i := 1;i <= num ; i ++ {
		boy := &Boy{
			No: i,
		}

		// 分析构成循环链表,需要一个辅助指针
		// 因为第一个小孩比较特殊
		if i == 1{
			first = boy  // 不要动
			temp = boy
			temp.Next = first
		} else {
			temp.Next = boy
			temp = boy
			temp.Next = first  // 构成环形链表
		}
	}
	return first
}

// 显示单向环形链表
func ShowBoy(first *Boy){
	// 判断环形链表是否为空
	if first.Next == nil {
		fmt.Println("链表为空,没有小孩。。。")
		return
	}

	// 创建一个指针,帮助遍历
	temp := first
	for {
		fmt.Printf("小孩编号=%d->",temp.No)
		if temp.Next == first{
			break
		}
		temp = temp.Next
	}
}

func PlayGame(first *Boy, startNo int, countNum int){
	// 判断是否为空
	if first.Next == nil {
		fmt.Println("空空如也")
		return
	}

	// 需要定义辅助指针,来帮助我们删除小孩
	temp := first
	// 让temp找到最后一个小孩,在删小孩时候需要使用到
	for{
		if temp.Next == first{
			// 说明已经到了最后一个小孩
			break
		}
		temp = temp.Next
	}

	// 让first移动到startNo
	for i := 0; i <= startNo; i ++{
		first = first.Next
		temp = temp.Next
	}
	for{
		// 开始数countNum,然后删除first指向的小孩
		for i := 1; i <= countNum - 1; i ++ {
			first = first.Next
			temp = temp.Next
		}

		fmt.Printf("小孩编号为%d出圈\n",first.No)
		// 删除
		first = first.Next
		temp.Next = first

		// 判断如果temp == first,则只剩下一个小孩
		if temp == first{
			break
		}
	}
	fmt.Printf("最后一个小孩编号为%d\n",first.No)
}


func main() {
	first := AddBoy(500)
	ShowBoy(first)
	PlayGame(first,20,31)
}
posted @ 2021-03-01 10:40  李大鹅  阅读(65)  评论(0编辑  收藏  举报