上一节课 我们讲到了基本的堆和队列,不明白的同学可回过头再学习一下,这一节课,我们花时间重点讲一下线性结构
在讲数组之前,我们先回顾下开发者常用的数组
数组其实是一种线性表的顺序存储结构,它的特点是用一组地址连续的存储单元依次存储数据元素。而它的缺点也正是其特点而造成,比如对数组做删除或者插入的时候,可能需要移动大量的元素。
这里大致模拟一下数组的插入操作:
function insert(arr, index, data) {
for (let i = arr.length; i >index; i--) {
arr[i] = arr[i - 1];
}
arr[index] = data;
}
从上面的代码可以看出数组的插入以及删除都有可能会是一个O(n)的操作。从而就引出了链表这种数据结构,链表不要求逻辑上相邻的元素在物理位置上也相邻,因此它没有顺序存储结构所具有的缺点,当然它也失去了数组在一块连续空间内随机存取的优点。
链表又分单项链表 双向链表及循环链表 这节课我们从基本的入手,先讲单项链表
单向链表的特点:
- 用一组任意的内存空间去存储数据元素(这里的内存空间可以是连续的,也可以是不连续的)
- 每个节点(node)都由数据本身和一个指向后续节点的指针组成
- 整个链表的存取必须从头指针开始,头指针指向第一个节点
- 最后一个节点的指针指向空(NULL)
链表中的几个主要操作
- 创建节点
- 插入节点
- 搜索/遍历节点
- 删除节点
- 合并
初始化节点
- 指针指向空
- 存储数据
class Node {
constructor(key) {
this.key = key;
this.next = null;
}
}
**
初始化链表
-
头节点为空
-
链表长度为0
class List {
constructor() {
this.head = null;
this.length = 0;
}
插入节点(在尾部插入节点)
- 插入操作只需要去调整节点的指针即可,两种情况:
- head没有指向任何节点,说明当前插入的节点是第一个
- head指向新节点
- 新节点的指针指向NULL
- head有指向的节点
-
head指向新的节点
-
新节点的指针指向原本head所指向的节点
// 往尾部插入数据
-
append(ele) {
const node = new Node(ele);
if (this.head) {
let current = this.head;
while (current.next) {
current = current.next
}
current.next = node;
} else {
this.head = node;
}
this.length++;
}
任意位置插入元素
insert(index, ele) {
if (index > -1 && index < this.length) {
const node = new Node(ele);
let current = this.head;
let previous = null;
let idx = 1;
if (this.head != 0) {
while (idx < index) {
previous = current;
current = current.next;
idx++;
}
node.next = current;
previous.next = node;
this.length++;
} else {
this.head = node;
}
} else {
console.error(`请输入0到${this.length}的值`);
return false
}
}
// 移除指定位置元素
removeAt(index) {
if (index > -1 && index < this.length) {
let previous = null;
let current = this.head;
let idx = 0;
if (index == 0) {
this.head = current.next;
} else {
while (idx < index) {
previous = current;
current = current.next;
idx++;
}
previous.next = current.next;
}
this.length--;
return current.key;
} else {
console.error(`请输入0到${this.length}的值`);
return false
}
}
搜索节点
- 从head开始查找
- 找到节点中的key等于想要查找的key的时候,返回该节点
// 寻找元素下标
findIndex(ele) {
let current = this.head;
let index = 0;
while (index < this.length) {
if (current.key == ele) {
return index + 1;
} else {
current = current.next;
index++;
}
}
return -1
}
isEmpty() {
return !this.length;
}
// 转为字符串
toString() {
let str = "";
let current = this.head;
while (current) {
str = str + current.key;
current = current.next;
}
return str;
}
}
完整的代码块如下
class Node {
constructor(key) {
this.key = key;
this.next = null;
}
}
class List {
constructor() {
this.head = null;
this.length = 0;
}
// 往尾部插入数据
append(ele) {
const node = new Node(ele);
if (this.head) {
let current = this.head;
while (current.next) {
current = current.next
}
current.next = node;
} else {
this.head = node;
}
this.length++;
}
// 任意位置插入元素
insert(index, ele) {
if (index > -1 && index < this.length) {
const node = new Node(ele);
let current = this.head;
let previous = null;
let idx = 1;
if (this.head != 0) {
while (idx < index) {
previous = current;
current = current.next;
idx++;
}
node.next = current;
previous.next = node;
this.length++;
} else {
this.head = node;
}
} else {
console.error(`请输入0到${this.length}的值`);
return false
}
}
// 移除指定位置元素
removeAt(index) {
if (index > -1 && index < this.length) {
let previous = null;
let current = this.head;
let idx = 0;
if (index == 0) {
this.head = current.next;
} else {
while (idx < index) {
previous = current;
current = current.next;
idx++;
}
previous.next = current.next;
}
this.length--;
return current.key;
} else {
console.error(`请输入0到${this.length}的值`);
return false
}
}
// 寻找元素下标
findIndex(ele) {
let current = this.head;
let index = 0;
while (index < this.length) {
if (current.key == ele) {
return index + 1;
} else {
current = current.next;
index++;
}
}
return -1
}
isEmpty() {
return !this.length;
}
// 转为字符串
toString() {
let str = "";
let current = this.head;
while (current) {
str = str + current.key;
current = current.next;
}
return str;
}
}
const list = new List();
console.log(list);
list.append(2);
list.append(6);
list.append(24);
list.append(152);
list.insert(3, 18);
console.log(list);
console.log(list.findIndex(24));
console.log(list.removeAt(1));
console.log(list)
这节课我们就讲到这里,不好之处,欢迎大家留言。
*[上一篇:高级前端之js数据结构与算法](https://blog.csdn.net/weixin_43097944/article/details/115027768)*