初识Go语言24-数据结构与算法【链表、栈】


数据结构与算法

链表

在这里插入图片描述

---手写单链表
type Node struct {
    
    
	Info int
	Next *Node
}

type List struct {
    
    
	Head *Node
	Len  int
	Tail *Node
}

func (list *List) Add(ele int) {
    
    
	node := &Node{
    
    Info: ele, Next: nil}
	if list.Len == 0 {
    
    
		list.Head = node
		list.Tail = node //尾指针
	} else {
    
    
		// head:=list.Head
		// for i:=1;i<list.Len;i++{
    
    
		// 	head = head.Next
		// }
		list.Tail.Next = node
		list.Tail = node
	}
	list.Len += 1
}

func (list List) Travs() {
    
    
	if list.Len == 0 {
    
    
		return
	}
	head := list.Head
	fmt.Printf("%d ", head.Info)
	for i := 1; i < list.Len; i++ {
    
    
		head = head.Next
		fmt.Printf("%d ", head.Info)
	}
}

  链表的一个应用案例。LRU(Least Recently Used, 最近最少使用)缓存淘汰的总体思路:缓存的key放到链表中,头部的元素表示最近刚使用。

  • 如果命中缓存,从链表中找到对应的key,移到链表头部。

  • 如果没命中缓存:

    • 如果缓存容量没超,放入缓存,并把key放到链表头部。

    • 如果超出缓存容量,删除链表尾部元素,再把key放到链表头部。

    • 基于手写双链表粗略实现LRU算法

    ---基于双链表实现LRU算法(TODO:往链表中添加元素时的判断)
    type Node struct {
          
          
    	Info int
    	Next *Node
    	Prev *Node
    }
    
    type List struct {
          
          
    	Head *Node
    	Len  int
    	Tail *Node
    }
    
    func (list *List) Add(ele int) {
          
          
    	node := &Node{
          
          Info: ele, Next: nil, Prev: nil}
    	if list.Len == 0 {
          
          
    		list.Head = node
    		list.Tail = node //尾指针
    	} else {
          
          
    		list.Tail.Next = node
    		node.Prev = list.Tail
    		list.Tail = node
    	}
    	list.Len += 1
    }
    
    func (list List) Travs() {
          
          
    	if list.Len == 0 {
          
          
    		return
    	}
    	head := list.Head
    	fmt.Printf("%d ", head.Info)
    	for i := 1; i < list.Len; i++ {
          
          
    		head = head.Next
    		fmt.Printf("%d ", head.Info)
    	}
    	fmt.Println()
    }
    
    func (list *List) Visit(ele int) {
          
          
    	if list.Len == 0 {
          
          
    		return
    	}
    	head := list.Head
    	for {
          
          
    		if head == nil {
          
          
    			break
    		}
    		if head.Info != ele {
          
          
    			head = head.Next
    		} else {
          
          
    			break
    		}
    	}
    	if head == nil {
          
          
    		return
    	} else {
          
           // 1-->8-->7-->5  改为7-->1-->8-->5
    		post := head.Next //5
    		pre := head.Prev  //8
    
    		pre.Next = post //8-->5
    		post.Prev = pre //5-->8
    
    		head.Next = list.Head // 7-->1
    		list.Head.Prev = head // 1-->7
    		list.Head = head      //7成链表的头部
    	}
    }
    
    

go list的使用

type Element

type Element struct {
    // 元素保管的值
    Value interface{}
    // 内含隐藏或非导出字段
}

Element类型代表是双向链表的一个元素。


func (*Element) Next

func (e *Element) Next() *Element

Next返回链表的后一个元素或者nil。


func (*Element) Prev

func (e *Element) Prev() *Element

Prev返回链表的前一个元素或者nil。


type List

type List struct {
    // 内含隐藏或非导出字段
}

List代表一个双向链表。List零值为一个空的、可用的链表。


func New

func New() *List

New创建一个链表。


func (*List) Init

func (l *List) Init() *List

Init清空链表。


func (*List) Len

func (l *List) Len() int

Len返回链表中元素的个数,复杂度O(1)。


func (*List) Front

func (l *List) Front() *Element

Front返回链表第一个元素或nil。


func (*List) Back

func (l *List) Back() *Element

Back返回链表最后一个元素或nil。


func (*List) PushFront

func (l *List) PushFront(v interface{}) *Element

PushBack将一个值为v的新元素插入链表的第一个位置,返回生成的新元素。


func (*List) PushFrontList

func (l *List) PushFrontList(other *List)

PushFrontList创建链表other的拷贝,并将拷贝的最后一个位置连接到链表l的第一个位置。

func (*List) PushBack

func (l *List) PushBack(v interface{}) *Element

PushBack将一个值为v的新元素插入链表的最后一个位置,返回生成的新元素。


func (*List) PushBackList

func (l *List) PushBackList(other *List)

PushBack创建链表other的拷贝,并将链表l的最后一个位置连接到拷贝的第一个位置。


func (*List) InsertBefore

func (l *List) InsertBefore(v interface{}, mark *Element) *Element

InsertBefore将一个值为v的新元素插入到mark前面,并返回生成的新元素。如果mark不是l的元素,l不会被修改。


func (*List) InsertAfter

func (l *List) InsertAfter(v interface{}, mark *Element) *Element

InsertAfter将一个值为v的新元素插入到mark后面,并返回新生成的元素。如果mark不是l的元素,l不会被修改。


func (*List) MoveToFront

func (l *List) MoveToFront(e *Element)

MoveToFront将元素e移动到链表的第一个位置,如果e不是l的元素,l不会被修改。


func (*List) MoveToBack

func (l *List) MoveToBack(e *Element)

MoveToBack将元素e移动到链表的最后一个位置,如果e不是l的元素,l不会被修改。


func (*List) MoveBefore

func (l *List) MoveBefore(e, mark *Element)

MoveBefore将元素e移动到mark的前面。如果e或mark不是l的元素,或者e==mark,l不会被修改。


func (*List) MoveAfter

func (l *List) MoveAfter(e, mark *Element)

MoveAfter将元素e移动到mark的后面。如果e或mark不是l的元素,或者e==mark,l不会被修改。

func (*List) Remove

func (l *List) Remove(e *Element) interface{}

Remove删除链表中的元素e,并返回e.Value。

	lst := list.New() // 创建一个空的双向链表
	lst.PushBack(4)
	lst.PushBack(6)
	lst.PushBack(2)
	lst.PushFront(9)//往链表头部添加
	TravsList(lst)// 9 4 6 2

func TravsList(lst *list.List) {
    
    
	head := lst.Front()
	for head.Next() != nil {
    
    
		fmt.Printf("%v ", head.Value)
		head = head.Next()
	}
	fmt.Printf("%v \n", head.Value)
}

在这里插入图片描述

  ring的应用:基于滑动窗口的统计。比如最近100次接口调用的平均耗时、最近10笔订单的平均值、最近30个交易日股票的最高点。ring的容量即为滑动窗口的大小,把待观察变量按时间顺序不停地写入ring即可。

package main

import (
	"container/ring"
	"fmt"
)

func TraverseRing(ring *ring.Ring) {
    
    
	ring.Do(func(i interface{
    
    }) {
    
     //通过Do()来遍历ring,内部实际上调用了Next()而非Prev()
		fmt.Printf("%v ", i)
	})
	fmt.Println()
}

func main() {
    
    
	ring := ring.New(5) //必须指定长度,各元素被初始化为nil
	ring2 := ring.Prev()
	for i := 0; i < 3; i++ {
    
    
		ring.Value = i
		ring = ring.Next()
	}
	for i := 0; i < 3; i++ {
    
    
		ring2.Value = i
		ring2 = ring2.Prev()
	}
	TraverseRing(ring)
	TraverseRing(ring2) //ring和ring2当前所在的指针位置不同,所以遍历出来的顺序也不同
}

  栈是一种先进后出的数据结构,push把元素压入栈底,pop弹出栈顶的元素。编程语言的编译系统也用到了栈的思想。

在这里插入图片描述

  go自带的List已经包含了栈的功能,这里实现一个线程安全的栈。

type (
	node struct {
    
    
		value interface{
    
    }
		prev  *node
	}
	MyStack struct {
    
    
		top    *node
		length int
		lock   *sync.RWMutex
	}
)

func NewMyStack() *MyStack {
    
    
	return &MyStack{
    
    nil, 0, &sync.RWMutex{
    
    }}
}

func (stack *MyStack) Push(value interface{
    
    }) {
    
    
	stack.lock.Lock()
	defer stack.lock.Unlock()
	n := &node{
    
    value, stack.top}
	stack.top = n
	stack.length++
}

func (stack *MyStack) Pop() interface{
    
    } {
    
    
	stack.lock.Lock()
	defer stack.lock.Unlock()
	if stack.length == 0 {
    
    
		return nil
	}
	n := stack.top
	stack.top = n.prev
	stack.length--
	return n.value
}

func (stack *MyStack) Peak() interface{
    
    } {
    
    
	stack.lock.RLock()
	defer stack.lock.RUnlock()
	if stack.length == 0 {
    
    
		return nil
	}
	return stack.top.value
}

func (stack *MyStack) Len() int {
    
    
	return stack.length
}

func (stack *MyStack) Empty() bool {
    
    
	return stack.Len() == 0
}

猜你喜欢

转载自blog.csdn.net/m0_52896752/article/details/131461865