链表
链表是一种物理存储单元上非连续、非顺序的存储结构。
-
链表上的节点的逻辑顺序是通过链表中的指针链接来实现的
-
链表的查找依赖辅助指针来完成
-
链表上的结点包括两个部分:
- 一个是存储数据的数据域
- 一个是存储链接指向的指针域
-
链表在插入操作时,最快可以达到O(1)的时间复杂度
- 在得到要插入位置的结点的指针后,直接链接进去,然后将前后两个结点的数据交换,即可实现O(1)时间复杂度的速度。
-
结构图:
下面分析几种操作: -
查找
- 通过分析链表的存储方式可知(按照指针依次链接n个对象), 查找元素只能挨个查找,直至找到目标元素。时间复杂度达到O(n)
-
添加
- 添加结点是将结点链接到链表尾部,因此需要查找的链接尾部结点
-
插入
- 插入方式如下图,需要找到目标位置的结点以及该位置的前一个结点,然后将前一个结点的指针指向新结点,新结点的指针指向目标位置的结点
- 因实现插入操作需要获得两个结点,于是需要创建两个指针来获取这两个结点
-
删除
- 删除操作如下图所示,找到目标结点及其上一个结点,然后将上一个结点的指针指向目标结点的下一个结点。
- 删除操作如下图所示,找到目标结点及其上一个结点,然后将上一个结点的指针指向目标结点的下一个结点。
完整代码:
//封装链表的构造函数
function LinkedList() {
/* 节点构造函数 */
function Node(data) {
this.data = data;
this.next = null;
}
this.length = 0;
/* 头指针 */
this.head = null;
//1.添加方法
LinkedList.prototype.append = function (data) {
/* 创建节点 */
let newNode = new Node(data);
// 因为要找到尾节点来链接新节点,因此要创建一个指针来获得尾节点
let current = this.head;
//如果空链表则直接将头指针指向新节点
if (this.head === null) {
this.head = newNode;
} else {
//
while (!current.next) {
current = current.next;
}
current.next = newNode;
}
}
//2.插入方法
LinkedList.prototype.insert = function (position, data) {
/* 创建节点 */
let newNode = new Node(data);
/*
因为插入节点的方法是获取到插入位置的节点和上一个节点,
然后上一个节点指向新节点,新节点指向插入位置所在的节点。
因此要创建两个指针来获取两个节点并进行操作.
并且通过索引来确定插在哪个位置,因此要创建索引
*/
let current = this.head;
let previous = null;
let index = 0;
if (position == 0) {
newNode.next = current;
this.head = newNode;
} else {
while (index <= position) {
index++;
previous = current;
current = current.next;
}
previous.next = newNode;
newNode.next = current;
}
this.length++;
}
//3.移除方法
LinkedList.prototype.remove = function (position) {
/* 创建节点 */
let newNode = new Node(data);
/*
移除节点的方法是目标节点的上一个节点指向目标节点的下一个节点,
因此需要创建两个指针来获取两个节点并进行相应操作。
并且是根据索引来确定要删除的节点,
因此要创建各个节点的index索引来进行比较。
*/
let index = 0;
let current = this.head;
let previous = null;
//如果要删除第一个节点,则直接让头指针指向第二个节点即可
if (position == 0) {
this.head = newNode;
} else {
while (index <= position) {
index++;
previous = current;
current = current.next;
}
previous.next = current.next;
}
this.length--;
}
}