回顾
第一天我们学习了栈和队列[数据结构与算法-小白系列]第1️⃣天栈、队列
今天我们来学习下另外一种重要的数据结构链表,个人感觉链表理解起来比栈和队列要难,但不管咱们样 干就完了
链表和栈,队列有着本质不同
在上一篇中,我们是通过javascript数组实现的栈和队列,我们知道,数组是线性结构,也就是说数组中的数据是一个一个连续的存放的,我们可以通过下标来读取元素,所以栈和队列都是线性储存数据的,而链表就不是了,我们可以先记着链表是链式存储的线性表
链表是为了解决什么问题?
存在是有原因的,我们要记着 每一种数据结构都对应着一种典型的应用场景
那链表是为了解决什么问题呢?
我们先来盘盘栈和队列这种数据结构有什么缺点,也可以说数组有什么缺点
首先数组是线性存储数据,可以通过下标来读取数据,固然它的 读取速度非常高,但是如果我们向数据里面新增或删除数据,数据的执行效率就不那么高了,下面我们来看看向数组里面新增数据的过程
有个数组[2,4,6,8],现在我们需要在2,4之间新增一个3
可以看出我们在插入一个数据的同时,需要改变三个数据的位置,那如果数据量非常大呢,可见 数组在新增和修改数据的时候效率比较低
而链表就是为了解决这个问题而生
链表的结构
链表的精髓在于指针,我们可以把链表中的元素称之为节点,每个节点之间都是通过指针建立关系
那问题来了,为什么要通过指针建立关系呢?
这就要研究下链表是如何存储数据的了,我们知道数组存储是连续的,所以可以通过数组的索引拿到值,而链表的存储数据是离散的,那我们如何知道一个节点下个数据是什么呢?那就只能通过指针,买个节点都保存下个节点的引用,如下所示:
现在如果我们要添加内容只需要移动指针就可以了,如下我们要在2和3中添加一个4
现在的数据结构为1->2->4->3如果要删除元素4的话直接让2的指针直接指向3即可 1->2->3
原理很简单,下面就让我们用代码实现一边把
使用JavaScript实现链表
单向链表
单向列表就是每个节点都保存的有指向下一个节点的引用,这个指向只能是单向的,比如 1->2->3->4,那我们用代码怎么实现呢?
首先我们要创建一个节点
function Node(data){
this.data = data
this.next = null
}
我们封装一个链表类,其中有以下几个方法:
- append 追加
- insert 插入
- get 获取对应下标的数据
- indexof 获取对应数据下标值
- updata 跟新节点
- remove 删除节点
- toString 链表字符串化
function linkedList() {
//链表的节点类
function Node(data) {
this.data = data;
this.next = null;
}
this.head = null; // 链表的hede 可以理解为指针
this.length = 0; //链表的长度
// 添加方法
linkedList.prototype.append = function(data) {
var newNode = new Node(data);
// 判断现在的链表是不是空
if (this.length == 0) {
// 添加的是第一个节点
this.head = newNode;
} else {
// 不是第一个节点,找到最后一个节点,在其后面追加节点
var current = this.head;
while (current.next) {
current = current.next; //一直往下找
}
// 追加最后一个节点
current.next = newNode;
}
this.length++;
};
// 插入方法,可以把数据插入到链表的任何地方
linkedList.prototype.insert = function(position, data) {
// 对 position 越界判断
if (position < 0 || position > this.length) {
return false;
}
var newNode = new Node(data);
// 判断是不是插入到第一个
if (position == 0) {
newNode.next = this.head;
this.head = newNode;
} else {
var index = 0;
var current = this.head;
var previous = null; // 记录上一个节点
while (index++ < position) {
previous = current;
current = current.next;
}
newNode.next = current;
previous.next = newNode;
}
this.length++;
return true;
};
// 获取对应位置上的数据
linkedList.prototype.get = function(position) {
if (position < 0 || position >= this.length) {
return null;
}
var current = this.head;
var index = 0;
while (index++ < position) {
current = current.next;
}
return current.next;
};
// 获取对应数据的下标值
linkedList.prototype.indexOf = function(data) {
var current = this.head;
var index = 0;
while (current) {
if (current.data == data) {
return index;
}
current = current.next;
index++;
}
return -1;
};
// 更新方法
linkedList.prototype.updata = function(position, data) {
if (position < 0 || position >= this.length) {
return false;
}
var current = this.head;
var index = 0;
while (index++ < position) {
current = current.next;
}
current.data = data;
return true;
};
// 根据位置 删除元素
linkedList.prototype.removeAt = function(position) {
if (position < 0 || position >= this.length) {
return false;
}
// 删除第一个
if (position == 0) {
this.head = this.head.next;
} else {
var current = this.head;
var previous = null;
var index = 0;
while (index++ < position) {
position = current;
current = current.next;
}
previous.next = current.next;
}
this.length -= 1;
return true;
};
// 字符串化
linkedList.prototype.toString = function() {
var current = this.head;
var listString = "";
// 循环获取一个个节点
while (current) {
listString += current.data + " ";
current = current.next;
}
return listString;
};
}
双向链表
每个节点都记录了他上一个和下一个节点的引用,如:
把单向链表的的方法改为双向链表实现如下:
// 双向链表
function DoublyList() {
this.head = null; //指针 指向第一个
this.tail = null; // 指针 指向最后一个
this.length = 0; // 列表的长度
// 内部节点类
function Node(data) {
this.data = data;
this.prev = null;
this.next = null;
}
// 插入到链表的尾部
DoublyList.prototype.append = function(data) {
// 判断是否添加的第一个节点
var newNode = new Node(data);
if (this.length == 0) {
this.head = newNode;
this.tail = newNode;
} else {
newNode.prev = this.tail;
this.tail.next = newNode;
this.tail = newNode;
}
this.length += 1;
};
// 插入
DoublyList.prototype.insert = function(position, data) {
if (position < 0 || position > this.length) return false;
var newNode = new Node(data);
// 插入的节点是第一个节点
if (this.length == 0) {
this.head = newNode;
this.tail = newNode;
}
if (position == 0) {
this.head.prev = newNode;
newNode.next = this.head;
this.head = newNode;
} else if (position == this.length) {
newNode.prev = this.tail;
this.tail.next = newNode;
this.tail = newNode;
} else {
var current = this.head;
var index = 0;
while (index++ < position) {
current = current.next;
}
// 更改对应指针指向
newNode.next = current;
newNode.prev = current.prev;
current.prev.next = newNode;
current.prev = newNode;
}
this.length += 1;
};
// 获取对应下标的数据
DoublyList.prototype.get = function(position) {
if (position < 0 || position >= this.length) return false;
// 获取元素
var current = this.head;
var index = 0;
while (index++ < position) {
current = current.next;
}
return current.data;
};
// 获取对应值的下标
DoublyList.prototype.indexOf = function(data) {
var current = this.head;
var index = 0;
while (current) {
if (current.data == data) {
return index;
}
index++;
current = current.next;
}
return -1;
};
// 根据下标更新
DoublyList.prototype.updata = function(position, newData) {
if (position < 0 || position >= this.length) return false;
// 获取元素
var current = this.head;
var index = 0;
while (index++ < position) {
current = current.next;
}
current.data = newData;
return true;
};
// 根据下标删除
DoublyList.prototype.removeAt = function(position) {
if (position < 0 || position > this.length) return false;
if (this.length == 1) {
this.head = null;
this.tail = null;
}
if (position == 0) {
this.head.next.prev = null;
this.head = this.head.next;
} else if (position == this.length - 1) {
this.tail.prev.next = null;
this.tail = this.tail.prev;
} else {
var index = 0;
var current = this.head;
while (index++ < position) {
current = current.next;
}
current.prev.next = current.next;
current.next.prev = current.prev;
}
};
DoublyList.prototype.toString = function() {
return this.bacckwardToString();
};
// 从后向前遍历
DoublyList.prototype.forwardToString = function() {
var current = this.tail;
var resString = "";
while (current) {
current = current.prev;
resString += current.data + " ";
}
return resString;
};
// 从前向后遍历
DoublyList.prototype.bacckwardToString = function() {
var current = this.head;
var resString = "";
while (current) {
current = current.next;
resString += current.data + " ";
}
return resString;
};
}
最后
点个👍希望和你交个朋友