zoukankan      html  css  js  c++  java
  • 链表

    链表

    链表与数组的对比

    • 存储
      • 数组需要一块连续的内存空间来存储
      • 链表不需要一块连续的内存空间,而是通过“指针”将一组零散的内存块串联起来

    链表结构

    单链表

    • 结点
      • 链表的每个结点,除了存储数据,还需要记录链上下一个结点的地址
    • 后继指针 next
      • 记录下一个结点地址的指针叫做后继指针
    • 头节点
      • 记录链表的基地址,可以通过基地址遍历得到整条链表
    • 尾结点
      • 尾结点的指针不是指向下一个结点,而是指向一个空地址NULL,表示这是链上的最后一个

    链表的操作

    • 支持数据的查找、插入和删除操作
      • 在链表中插入和删除一个数据的时间复杂度是O(1)
      • 链表查找需要O(n)的时间复杂度

    双向链表

    双向链表是一种特殊的单链表。跟单链表的区别是尾结点。
    单链表的尾结点指向空地址,表示为最后的节点。
    循环链表的尾结点指针指向链表的头节点。

    循环链表

    单链表只有一个方向,节点只有一个后继指针指向后面的节点。
    双向链表有两个方向,每个结点除了一个后继指针next指向后面的结点,还有一个前驱指针prev指向前面的节点。

    应用场景

    LRU缓存淘汰算法

    • 链表的一个经典应用场景是LRU缓存淘汰算法
      缓存淘汰算法用来解决在有限大小的缓存内,当缓存用满时,数据的清理策略。常见的缓存淘汰策略有三种:

      • 先进先出策略FIFO(First In, First Out)
      • 最少使用策略LFU(Least Frequently Used)
      • 最近最少使用策略LRU(Least Recently Used)
    • 我们通过力扣上的一道题来看如何应用
      Leetcode LRU缓存机制

    • GO实现

    package main
    
    import "fmt"
    
    //LRU HashLink
    type LRUCache struct {
        hashmap map[int]*LinkNode
        LinkList LinkList
    }
    
    //链表
    type LinkList struct {
        head *LinkNode//指向第一个节点,通过遍历节点next到所有节点
        tail *LinkNode//指向最后一个节点,通过遍历prev到所有节点
        size int
        capacity int
    }
    
    //链表节点
    type LinkNode struct {
        key int//对应map中的key
        value int
        prev *LinkNode
        next *LinkNode
    }
    
    func Constructor(capacity int) LRUCache {
        var LRUCache LRUCache
        LRUCache.InitLink(capacity)
        return LRUCache
    }
    
    func (this *LRUCache) Get(key int) int {
        if(this.hashmap[key]==nil) {
            return -1
        }
        //放到最新
        this.MakeNodeRecenty(key)
        return this.hashmap[key].value
    }
    
    func (this *LRUCache) Put(key int, value int)  {
        if(this.hashmap[key]!=nil) {
            this.RemoveLink(key)
        }
        this.AddLink(key,value)
    }
    
    //初始化链表
    func (l *LRUCache) InitLink(capacity int) {
        l.hashmap = make(map[int]*LinkNode)
    
        head := &LinkNode{}
        tail := &LinkNode{}
    
        l.LinkList.head = head
        l.LinkList.tail = tail
    
        l.LinkList.head.next = tail
        l.LinkList.tail.prev = head
    
        l.LinkList.size = 0
        l.LinkList.capacity = capacity
    }
    
    //添加链表节点
    //添加到链表尾部
    //尾部节点即是最新的节点
    func (l *LRUCache) AddLink(key int, value int) {
        //存储已满,删除旧的一个节点
        if(l.LinkList.size>=l.LinkList.capacity) {
            l.RemoveLastLink()
        }
    
        newNode := &LinkNode{}
        newNode.key = key
        newNode.value = value
        l.LinkList.size++
        l.hashmap[key] = newNode
    }
    
    //将节点放到最新位置
    func (l *LRUCache) MakeNodeRecenty(key int) {
        node := l.hashmap[key]
        value := node.value
        l.RemoveLink(key)
        l.AddLink(key, value)
    }
    
    //删除指定key
    func (l *LRUCache) RemoveLink(key int) {
        node := l.hashmap[key]
    
        node.prev.next = node.next
        node.next.prev = node.prev
    
        l.hashmap[key] = nil
        l.LinkList.size--
    }
    
    //删除最旧的节点
    //最旧的节点即是头部节点
    func (l *LRUCache) RemoveLastLink() {
        node := l.LinkList.head.next
        key := node.key
        node.next.prev = node.prev
        node.prev.next = node.next
        l.hashmap[key] = nil
        l.LinkList.size--
    }
    
    func main() {
        obj := Constructor(1)
        obj.Put(2,1)
        param_1 := obj.Get(2)
        obj.Put(3,2)
        param_2 := obj.Get(2)
        param_3 := obj.Get(3)
    
    
        fmt.Printf("%v", param_1)
        fmt.Printf("%v", param_2)
        fmt.Printf("%v", param_3)
    }
    

    链表反转

    • 同样我们通过力扣上的一道题来看看
      链表反转
    • GO实现
    /**
     * Definition for singly-linked list.
     * type ListNode struct {
     *     Val int
     *     Next *ListNode
     * }
     */
    func reverseList(head *ListNode) *ListNode {
        if(head == nil || head.Next==nil) {
            return head
        }
    
        current := head.Next
        prev := head
        prev.Next = nil
        for current!=nil {
            tmpnode := current.Next
            current.Next = prev
            prev = current
            current = tmpnode
        }
    
        head = prev
    
        return head
    }
    

    参考

    数据结构与算法之美
    大话数据结构

  • 相关阅读:
    How to Create a site at the specified URL and new database (CommandLine Operation)
    Using Wppackager to Package and Deploy Web Parts for Microsoft SharePoint Products and Technologies
    SQL Server Monitor v0.5 [Free tool]
    How to build Web Part
    Deploy web part in a virtual server by developing a Web Part Package file(.cab)
    How to recreate "sites" link if you delete it accidentally
    SharePoint Portal Server管理匿名访问设置
    Monitor sql connection from .Net SqlClient Data Provider
    Brief installation instruction of Sharepoint Portal Server
    How to Use SharePoint Alternate URL Access
  • 原文地址:https://www.cnblogs.com/biby/p/15208430.html
Copyright © 2011-2022 走看看