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))
}
golang go 关于链表的各种操作
最新推荐文章于 2021-07-01 10:22:32 发布