JS–学习链表
一、链表结构
1、单向链表
2、双向链表
3、单向循环链表
4、双向循环链表
5、链表与数组
数组:js中数组中可以存储不同数据类型的数据,查找元素很方便(随机访问),可以根据下标快速查找;但是删除、添加都比较复杂,会是数组中元素移动。
链表:查找数据不如数组方便,但是删除、插入等操作时会比较迅速,因为链表不需要移动多个元素,使用指针直接将元素添加进来或删除掉,但是空间会有部分浪费(使用部分空间存储指针,以空间换时间)
二、封装链表
1、单向链表
class NodeOne {
//每一个节点
constructor(element) {
this.data = element;//数据
this.next = null;//指针
}
}
//下标由0开始
class OneLinkList {
//单向链表
constructor() {
this.head = null;//头指针
this.length = 0;//链表长度
}
//添加节点
append(element) {
//创建一个新节点
let node = new NodeOne(element);
//this.head == null和this.length == 0都可以判断链表为空
if (this.head == null || this.length == 0) {
//链表为空时直接添加节点
this.head = node;
} else {
//链表部位空时找到尾部节点,在尾部节点后面添加节点
let current = this.head;
//找到next == null,不再往后找
while (current.next != null) {
//判断条件可以换为current.next
//next为空就继续往下找
current = current.next;
}
//next为空后就将next指向刚创建的新节点
current.next = node;
}
this.length++;//每添加一个节点就将链表长度+1
}
//在任意位置和它前一个之间插入节点
insert(element, position) {
if (position < 0 || position > this.length || !Number.isInteger(position)) {
return -1;
}
let node = new NodeOne(element);
let current = this.head;
if (position == 0) {
if (this.head == null || this.length == 0) {
this.head = node;
} else {
//链表不为空时插入到头部
current.next = this.head;//先将新的节点连接到头指针指向的节点
this.head = node;//再将头指针指向新的节点
}
} else if (position == this.length) {
this.append(node);
} else {
//方法一:
let current = this.head, index = 0;
while (index++ < position - 1) {
current = current.next;
}
node.next = current.next;
current.next = node;
//方法二:
// let current = this.head;
// let previous = null;
// let index = 0;
// while (index < position) {
// previous = current;
// current = current.next;
// index++;
// }
// node.next = current;
// previous.next = node;
}
this.length++;
}
//便于查看链表内容
toString() {
let listData = '';
let current = this.head;
while (current) {
listData += '-' + current.data;
current = current.next;
}
return listData.slice(1);
}
//根据数据查找节点
indexOf(element) {
let current = this.head;
let index = 0;
while (current) {
if (current.data === element) {
return index;
}
index++;
current = current.next;
}
return -1;
}
//移除特定位置的节点
removeAt(position) {
//不合法的位置返回-1
if (position < 0 || position > this.length || !Number.isInteger(position)) {
return -1;
}
//删除第一个
if (position == 0) {
//只有一个节点
if (this.length == 1) {
this.head = null;
} else {
//有多个节点
this.head = this.head.next;
}
// //删除最后一个
}else if(position == this.length - 1){
let current = this.head;
let index = 0;
while(index++ < position - 1){
current = current.next;
}
current.next = null;
//移除中间部分和尾部合并
} else {
let current = this.head;
let index = 0;
while (index++ < position) {
current = current.next;
}
current.next = current.next.next;
}
this.length--;
}
isEmpty(){
return this.length == 0;
}
size(){
return this.length;
}
remove(element){
return this.removeAt(this.indexOf(element));
}
}
2、双向链表
class DoubleNode {
constructor(element) {
this.data = element;
this.next = null;//下一个
this.previous = null;//前一个
}
}
class DoubleLinkList {
constructor() {
this.head = null;//头指针
this.length = 0;
this.tail = null;//尾指针
}
//添加节点
append(element) {
let node = new DoubleNode(element);
if (this.head == null) {
//链表为空时
this.head = node;
this.tail = node;
} else {
//不为空时
//前两句可以交换位置
this.tail.next = node;
node.previous = this.tail;
this.tail = node;
}
this.length++;
}
//正向遍历
toAfterString() {
let re = '';
let current