4. 链表
4.1 概念
-
线性数据结构,存储一系列的元素
-
不同于数组,链表中的元素在内存中不必是连续的空间
-
链表中每个元素存储元素本身的节点和指向下一个元素的引用
-
优点:
- 不必连续,便于实现灵活的内存动态管理
- 不必确定大小,可以无限延伸
- 插入和删除数据效率高,时间复杂度可达到O(1)
-
缺点:
- 访问元素需要从头开始,不能通过下标直接访问
4.2 封装与测试
-
常见操作
-
append(element)
向列表尾部添加新的项 -
insert(position,element)
特定位置插入新的项 -
get(position)
获取对应位置的元素 -
indexOf(element)
返回元素的索引,没有该元素则返回-1 -
update(position,element)
修改某个位置的元素 -
removeAt(position)
移除特定位置的元素 -
remove(element)
从链表中移除一项 -
isEmpty()
判断是否为空 -
size()
返回大小 -
toString()
输出元素的值
-
4.2.1 单向链表
-
封装
class Node{ constructor(element){ //保存元素 this.element = element; //下一个元素的引用 this.next = null; } } export class LinkedList{ constructor(){ this.head = null; this.length = 0; } append(element){ //1.创建Node对象 const newNode = new Node(element); //2.追加到最后 if(!this.head){ this.head = newNode; }else{ let current = this.head; while(current.next){ current = current.next; } current.next = newNode; } this.length++; } insert(position,element){ //1.判断越界 if(position < 0 || position >this.length) return false; //2.创建新的节点 const newNode = new Node(element); //3.插入元素 if(position === 0){ newNode.next = this.head; this.head = newNode }else{ let index = 0; let current = this.head; let previous = null; while(index++<position){ previous = current; current = current.next; } previous.next = newNode; newNode.next = current; } this.length++; return true; } get(position){ //1.判断越界 if(position<0||position>this.length-1)return null; //2.查找该位置的元素 let index = 0; let current = this.head; while(index++<position){ current = current.next; } return current.element; } indexOf(element){ //1.获取第一个元素 let current = this.head; let index = 0; //2.开始查找 while(current){ if(current.element === element){ return index; } index++; current = current.next; } return -1; } removeAt(position){ //1.判断越界 if(position<0||position>this.length-1)return null; //2.删除元素 let current = this.head; let previous = null; let index = 0; if(position === 0){ this.head = current.next; }else{ while(index++<position){ previous=current; current=current.next; } previous.next = current.next; } this.length--; return current.element; } update(position,element){ //删除 const result=this.removeAt(position); //插入 insert(positon,element); return result; } remove(element){ //1.获取index const index = this.indexOf(element); if(index === -1)return; //2.删除该位置的元素 this.removeAt(index); } isEmpty(){ return this.length === 0; } size(){ return this.length; } }
4.2.2 双向链表
-
特点:
- 可使用head和tail分别指向头部和尾部的节点
- 每个节点由三部分组成,有向前的引用也有向后的引用
- 插入删除元素需要处理四个引用
- 占据内存空间更大
-
常见操作(beyond单向链表)
forwardString()
返回正向遍历的节点字符串形式backwardString()
返回反向遍历的节点字符串形式
-
封装
//继承自单向链表 import {LinkedList,Node} from "" class DobuleNode extends Node{ constructor(element){ super(element);//初始化item和next this.prev=null;//定义前驱 } } export class DoubleLinkedList extends LinkedList{ constructor(){ super(); this.tail = null; } //重写部分方法 append(element){ const newNode = new DoubleNode(element); if(this.head === null){ this.head = newNode; this.tail = newNode; }else{ newNode.prev = this.tail; this.tail.next = newNode; this.tail = newNode; } this.length++; } insert(position,element){ if(position<0 || position>this.length){ return false; } const newNode = new Node(value); //插在第0位 if(position === 0){ if(this.head === null){ this.head = newNode; this.tail = newNode; }else{ newNode.next = this.head; this.head.prev = newNode; this.head = newNode; } //插在末尾 }else if(position === this.length){ newNode.prev = this.tail; this.tail.next = newNode; this.tail = newNode; //插在中间 }else{ let current = this.head; let index = 0; while(index<position){ current = current.next; index++; } newNode.prev = current.prev; newNode.next = current; current.prev.next = newNode; current.prev = newNode; } this.length++; return true; } removeAt(position){ if(position<0||position>=this.length){ return null; } let current = this.head; //去头 if(positon === 0){ this.head = current.next; if(this.length === 1){ this.tail = null; }else{ this.head.prev = null; } //去尾 }else if(position === this.length-1){ current = this.tail; this.tail = current.prev; this.tail.next = null //去中间 }else{ let index = 0; while(index<position){ current = current.next; index++; } current.prev.next = current.next; current.next.prev = current.prev; } this.length--; return current.value; } //其他方法均可以直接继承父类 }