持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
今天的学习记录!
心态崩溃的历程
早上起来,打算从头开始兴致勃勃的写一份数据结构的学习文档。谁知道一出门就碰到坑了。
拿js写了一份栈的数据结构
却因为导入时候没有写后缀嘎嘎报错
笨死了!!!
链表
首先链表是一种线性的数据结构。
以前我们学的相关数据结构,栈,队列,数组,等等都是依托静态数组完成的。
但链表都不同,链表是真正的最简单的动态的数据结构。
如果对链表有深刻的理解,就可以更容易的学习其他难以理解的数据结构了
同时学习链表可以更深入的理解引用(或者指针)
链表也有递归的结构,
链表的结构
数据存储在 “节点”(node)中
节点分为两部分
- 一部分存储这个节点的值,
- 另一部分指向另一个节点
就像一个车厢,车厢中有数据,然后车厢和车厢连着
优点: 真正的动态,不需要处理固定容量的问题
缺点: 丧失了随机访问的能力
链表的实现(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))
链表相关算法
链表的基础算法题主要就是节点之间指向的转换,还是比较好实现的
反转链表
while循环中的语句。相信大家都会
两两较换链表中的节点
难度也不是很大,主要也是用到了next的转换,
还有在链表中使用一个空的节点指向头部,很多时候都可以方便的解决很多问题
删除链表的倒数第N个节点
这道题也是比较简单的
使用双指针的方法,让快的指针先走n步,快慢指针相距n。然后当fast.next == null时,slow就到了指定的位置了,然后让slow.next = slow.next.next
算法待补充...
\