数据结构从入门到进阶(链表)

57 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

今天的学习记录!

心态崩溃的历程

早上起来,打算从头开始兴致勃勃的写一份数据结构的学习文档。谁知道一出门就碰到坑了。

拿js写了一份栈的数据结构

image.png

却因为导入时候没有写后缀嘎嘎报错

image.png 笨死了!!!

链表

首先链表是一种线性的数据结构。

以前我们学的相关数据结构,栈,队列,数组,等等都是依托静态数组完成的。

但链表都不同,链表是真正的最简单的动态的数据结构

如果对链表有深刻的理解,就可以更容易的学习其他难以理解的数据结构了

同时学习链表可以更深入的理解引用(或者指针)

链表也有递归的结构

链表的结构

数据存储在 “节点”(node)中

image-20220930160032991

节点分为两部分

  • 一部分存储这个节点的值,
  • 另一部分指向另一个节点

就像一个车厢,车厢中有数据,然后车厢和车厢连着

image-20220930160301200

优点: 真正的动态,不需要处理固定容量的问题

缺点: 丧失了随机访问的能力

链表的实现(js)

//先定义节点
class linkNode {
    val;
    next;
    constructor(val, next) {
        this.val = val;
        this.next = next
    }
}
​
//定义链表
//链表包含头指针,尾指针,和链表长度class linkedList {
    constructor() { //初始化一个空链表
        this._size = 0;
        this._head = null;  //头结点
        this._tail = null;  //尾节点
    }
    //在头节点前加入节点
    addAtHead(val) {
        let node = new linkNode(val, this._head)    //在头指针前加入,就算让这个节点指向头结点。 
        this._head = node       //因为实在最前面加入的,就是把加入的这个节点变成头结点
        this._size++
        if (!this._tail) {
            this._tail = node   //当通过这个方法创建第一个节点时,尾指针是空。这个元素就即时头指针也是尾指针。
        }
    }
​
    //在末尾加入节点
    addAtTail(val) {
        let node = new linkNode(val, null)
        if (this._tail) {           //当存在尾节点时,就可以直接改变尾指针的内容
            this._tail.next =  node(已修正)
            this._tail = node
        } else {                    //当不存在尾节点时,该表为空表,加入的这个节点即使头结点,又是尾节点
            this._tail = node
            this._head = node
        }
    }
​
    //在链表中的第 index 个节点之前添加值为 val 的节点。
    addAtIndex(index, val) {
        if (index > this._size) {
            return "索引不存在"
        }
        if (index == 0) {
            //当索引值时0时,复刻在头结点创建的过程
            let node = new linkNode(val, this._head)
            this._head = node
            this._size++
            if (!this._tail) {
                this._tail = node
            }
        }
        else {
            let courent = this._head
            let count = 0
            while (count < index - 1) {
                courent = courent.next
                count++
            }
            let node = new linkNode(val, courent.next)
            courent.next = node
            //如果时在链表尾部创建的话
            if (index == this._size) {
                this._tail = node
            }
            this._size++
        }
​
    }
​
    //根据索引获取节点,参数是 index 这里索引是从0开始的
    getByIndex(index) {
        if (index < 0 || index >= this._size) {
            return "索引无效"
        }
        let count = 0;
        let cur = this._head
        while (count != index) {
            cur = cur.next
            count++
        }
        return cur.val
    }
​
    //在删掉索引处的节点
    deleteAtIndex(index) {
        //先判断索引是否有效
        if (index < 0 || index >= this._size) {
            return "索引无效"
        }
​
        //删除头结点时:
        if (index == 0) {
            this._head = this._head.next
            //当链表只有一位时,即头结点和为节点相同就需要把头节点和尾节点都删掉
            if (this._size == 1) {
                this._tail = null
            }
            this._size--
        }
        //正常删除情况:
        else {
            var count = 0;
            var cur = this._head
            while (count != index - 1) {
                cur = cur.next
                count++
            }
            cur.next = cur.next.next
            //如果删除的时最后一个节点,需要改变尾节点的位置
            if (index + 1 == this._size) {
                this._tail = cur
            }
            this._size--
        }
​
​
    }
}
​
var listOne = new linkedList()
listOne.addAtHead(2)
listOne.addAtHead(5)
listOne.addAtHead(100)
listOne.addAtHead(5200)
listOne.addAtIndex(4, 111)
​
console.log(listOne)
// console.log(listOne._head.next)// console.log(listOne.getByIndex(1))
​
​

链表相关算法

链表的基础算法题主要就是节点之间指向的转换,还是比较好实现的

反转链表

image-20220930161212269

while循环中的语句。相信大家都会

两两较换链表中的节点

image-20220930161335623

image-20220930161419592

难度也不是很大,主要也是用到了next的转换,

还有在链表中使用一个空的节点指向头部,很多时候都可以方便的解决很多问题

删除链表的倒数第N个节点

image-20220930190929128

image-20220930190941198

这道题也是比较简单的

使用双指针的方法,让快的指针先走n步,快慢指针相距n。然后当fast.next == null时,slow就到了指定的位置了,然后让slow.next = slow.next.next

算法待补充...

\