Go语言数据结构-链表

定义

linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说的链表,结构有单向链表、双向链表和环形链表。

特点

查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素
增删元素快:添加或者删除某个元素,只要更换上一个节点和下一个节点就可以了

应用场景

  1. 结合哈希表:LRU 缓存、链地址法解决哈希冲突。
  2. 循环链表:约瑟夫问题

单向链表

在这里插入图片描述

基本结构和操作

//
// 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)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值