golang go 关于链表的各种操作


package main

import (
	"fmt"
)

/**
golang实现单链表
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。
链表中的数据以节点来表示,每个节点的构成:元素(数据元素的映像)+ 指针(指向后继元素存储位置)。元素是存储数据的存储单元,指针是连接每个节点的地址数据。
节点结构:
|--data--|--next--|
data域存放节点值的数据域,next域存放节点的直接后继地址(位置)的指针域(链域)
头指针head和终端节点
单链表中每个几点的存储地址是存放在其前趋节点next域中。而开始节点无前趋,所以应该设置头指针head指向开始节点。链表由头指针唯一确定,单链表可以用头指针的名字来命名。
终端节点无后继,所以终端节点的指针域为空,即NULL。
*/

type Node struct {
	// 值
	Data interface{}
	// 后继节点指针
	Next *Node
}

// 链表是否为空
func IsEmpty(node *Node) bool {
	return node == nil
}

// 是否是最后一个节点
func IsLast(node *Node) bool  {
	return node.Next == nil
}

// 查找指定节点的前一个节点
func FindPrevious(data interface{}, node *Node) *Node  {
	tmp := node
	for tmp.Next != nil && tmp.Next.Data != data {
		tmp = tmp.Next
	}
	return tmp
}
// 查找某个值在哪个节点
func Find(data interface{}, node *Node) *Node  {
	tmp := node
	for tmp.Data != data {
		tmp = tmp.Next
	}
	return tmp
}

// 插入节点:在指定节点插入节点
/**
position:指定的节点位置
*/
func Insert(data interface{}, position *Node)  {
	// 新建一个节点
	tmpCell := new(Node)
	if tmpCell == nil {
		fmt.Println("err: out of space")
	}
	// 给新建的节点的值域赋值为传入的data值
	tmpCell.Data = data
	// 新建的节点的next指针指向的是指定节点position的next
	tmpCell.Next = position.Next
	// 指定节点position的后继节点变成了新建的节点
	position.Next = tmpCell
}

// 删除节点
func Delete(data interface{}, node *Node)  {
	preview := FindPrevious(data, node)
	tmp := Find(data, node)
	preview.Next = tmp.Next
	tmp = nil
}

// 删除链表
func DeleteList(node **Node)  {
	p := node
	for *p != nil {
		tmp := *p
		*p = nil
		*p = tmp.Next
	}
}
//反转链表 递归
func ReverseList(node *Node) *Node{
	p :=node
	if p.Next==nil{
		return p
	}
	q:=ReverseList(p.Next)
	p.Next.Next=p
	p.Next=nil
	return q
}

//返回倒数第k个数 双指针法
func kthToLast(k int,node *Node) *Node{
	p := node
	q := node
	for ;k>0;k--{
		p=p.Next
	}
	for p!=nil{
		p=p.Next
		q=q.Next
	}
	return q
}

//返回倒数第k个数 递归
var size int //全局变量记录向后递归次数
func ZkthToLast(k int,node *Node) *Node{
	p:=node
	if p==nil{
		return p
	}
	t:=ZkthToLast(k,p.Next)
	size++
	if size==k{
		return p
	}
	if size<k{
		return t
	}
	if size>k{
		return t
	}
	return t
}
//反转链表 非递归
func NReverseList(node *Node) *Node{
	p :=node
	var cre *Node =nil
    for p!=nil{
		t:=p.Next
		p.Next=cre
		cre=p
		p=t
	}
	return cre
}

//打印列表
func PrintList(list *Node) {
	p := list
	for p != nil {
		fmt.Printf("%d-%v-%p ", p.Data, *p, p.Next)
		p = p.Next
	}
	fmt.Println()
}
/**LRU算法***************************************************/
//哈希表
type LRUCache struct {
	size int
	capacity int
	cache map[int]*DLinkedNode
	head, tail *DLinkedNode
}
//双向链表
type DLinkedNode struct {
	key, value int
	prev, next *DLinkedNode
}

func initDLinkedNode(key, value int) *DLinkedNode {
	return &DLinkedNode{
		key: key,
		value: value,
	}
}
//建一个空的双向链表
func Constructor(capacity int) LRUCache {
	l := LRUCache{
		cache: map[int]*DLinkedNode{},
		head: initDLinkedNode(0, 0),
		tail: initDLinkedNode(0, 0),
		capacity: capacity,
	}
	l.head.next = l.tail
	l.tail.prev = l.head
	return l
}
//取一个数
func (this *LRUCache) Get(key int) int {
	if _, ok := this.cache[key]; !ok {
		return -1
	}
	node := this.cache[key]
	//放到最前边
	this.moveToHead(node)
	return node.value
}

//加一个数
func (this *LRUCache) Put(key int, value int)  {
	//如果没有
	if _, ok := this.cache[key]; !ok {
		node := initDLinkedNode(key, value)
		this.cache[key] = node
		this.addToHead(node)
		this.size++
		if this.size > this.capacity {
			removed := this.removeTail()
			delete(this.cache, removed.key)
			this.size--
		}
	} else {
		node := this.cache[key]
		node.value = value
		this.moveToHead(node)
	}
}
//在前边添加
func (this *LRUCache) addToHead(node *DLinkedNode) {
	node.prev = this.head
	node.next = this.head.next
	this.head.next.prev = node
	this.head.next = node
}
//删除节点
func (this *LRUCache) removeNode(node *DLinkedNode) {
	node.prev.next = node.next
	node.next.prev = node.prev
}
//移到前方
func (this *LRUCache) moveToHead(node *DLinkedNode) {
	this.removeNode(node)
	this.addToHead(node)
}
//删除尾部
func (this *LRUCache) removeTail() *DLinkedNode {
	node := this.tail.prev
	this.removeNode(node)
	return node
}

/*!!!!!!!!!!!!!!!!!!!判断是否有环,判断入环点*/
//快慢指针
func detectCycle(head *Node) *Node {
	fast,slow:=head,head
	if fast==nil{
		return nil
	}
	for fast!=nil{
		if fast.Next==nil{
			return nil
		}
		fast = fast.Next.Next
		slow = slow.Next
		if fast==slow{
			break
		}
	}
	if fast==nil{
		return nil
	}
	for slow=head;slow!=fast;slow=slow.Next{
		fast=fast.Next
	}
	return fast
}
//*****************回文链表
// type ListNode struct {
//	 Val  int
//	 Next *ListNode
// }
//反转链表
func reverseList(head *Node) *Node {
	var prev, cur *Node = nil, head
	for cur != nil {
		nextTmp := cur.Next
		cur.Next = prev
		prev = cur
		cur = nextTmp
	}
	return prev
}
//找到前一半链表
func endOfFirstHalf(head *Node) *Node {
	fast := head
	slow := head
	for fast.Next != nil && fast.Next.Next != nil {
		fast = fast.Next.Next
		slow = slow.Next
	}
	return slow
}
//判断是否是回文链表
func isPalindrome(head *Node) bool {
	if head == nil {
		return true
	}

	// 找到前半部分链表的尾节点并反转后半部分链表
	firstHalfEnd := endOfFirstHalf(head)
	secondHalfStart := reverseList(firstHalfEnd.Next)

	// 判断是否回文
	p1 := head
	p2 := secondHalfStart
	result := true
	for result && p2 != nil {
		if p1.Data != p2.Data {
			result = false
		}
		p1 = p1.Next
		p2 = p2.Next
	}

	// 还原链表并返回结果
	firstHalfEnd.Next = reverseList(secondHalfStart)
	return result
}
//反转链表mn
func reverseBetween(head *Node, m int, n int) *Node {
	// 关键点是m的前一个节点
	dummy := &Node{
		Next: head,
	}
	prem := dummy
	for i := 1; i <= m-1; i++ {
		prem = prem.Next
	}

	// m和n区间内反转
	current := prem.Next
	var pre *Node
	for i := m; i <= n; i++ {
		tempNext := current.Next
		current.Next = pre
		pre = current
		current = tempNext
	}

	// prem.Next为m节点,原始m节点应该指向n+1节点
	prem.Next.Next = current
	// prem指向pre(反转之后的头节点)
	prem.Next = pre

	return dummy.Next
}

func main() {
	//定义头结点
	headNode := &Node{
		Data:0,
		Next:nil,
	}
	list := headNode
	//指定位置插入结点1
	Insert(1, headNode)
	//打印列表
	PrintList(list)
    //判断是否为空
	fmt.Println(IsEmpty(list))
	//是否是最后一个节点
	fmt.Println(IsLast(headNode))
	//查找某个值在哪个节点
	p := Find(0, list)
	fmt.Println(p)
	//插入数据
	Insert(2, p)
	PrintList(list)
	//删除结点
	//Delete(1, list)
	//PrintList(list)
	//删除链表
	//DeleteList(&list)
	//PrintList(list)
	//反转链表递归
	Reverselist:=ReverseList(list)
	PrintList(Reverselist)
	//反转链表非递归
	NReverselist:=NReverseList(Reverselist)
	PrintList(NReverselist)
	//返回倒数第k个数 双指针法
	kthToLast :=kthToLast(3,NReverselist)
	fmt.Println(kthToLast)
	//返回倒数第k个数 递归
	kthToLast = ZkthToLast(3,NReverselist)
	fmt.Println(kthToLast)
    //判断是否有环
    fmt.Println(detectCycle(NReverselist))
	//判断回文链表
	fmt.Println(isPalindrome(NReverselist))
	//反转链表mn
	PrintList(reverseBetween(NReverselist,0,1))
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值