链表概念
链表:链表是一种物理存储单元上非连续、非顺序的存储结构
,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域
,另一个是存储下一个结点地址的指针域
。
头结点:在单链表第一个元素结点之前设置的一个节点,数据域可以不存任何信息,指针域指向单链表第一个元素的结点。头结点不是链表必要元素。
头指针:指向单链表的第一个结点的指针,如果单链表有头结点,则头指针指向头结点,如果单链表没有头结点,则头指针指向第一个首元结点。头指针不能为空,头指针是链表的需要元素。
首元结点:单链表中第一个有数据元素的结点。如果单链表有头结点,则首元结点为头结点的下一个结点,如果单链表没有头结点,则首元结点为单链表的第一个结点。
单链表的实现
/* 定义单向链表结点类 */
class Node{
constructor(data){
this.data = data; //结点的数据域(数据成员)
this.next = null; //结点的指针域(指针成员)
}
}
/* 定义单向链表类 */
class SingleLinked{
constructor(){ //初始化链表
this.size = 0; //记录链表结点个数,开始时链表结点个数为0
this.head = new Node('head'); //链表头指针:记录链表的起始地址
}
//获取链表的长度
getLength(){
return this.size;
}
//判断链表是否为空
isEmpty(){
if(this.size === 0){
return '链表为空';
}else{
return '链表非空';
}
}
//遍历链表
displayList(){
var list = '';
var currentNode = this.head;//指向链表的头指针
while(currentNode){
list += currentNode.data;
currentNode = currentNode.next;//让指针指向当前节点的下一个节点
if(currentNode){
list += '->';
}
}
return list;
}
//获取链表的最后一个节点
findLast(){
var currentNode = this.head;
while(currentNode){
currentNode = currentNode.next;
}
return currentNode;
}
//采用尾插法给链表插入元素
appendNode(element){
var currentNode = this.findLast();//找到当前链表的最后一个节点
var newNode = new Node(Element);//创建一个新节点
currentNode.next = newNode;
newNode.next = null;
this.size++;//链表的长度加1
}
//删除一个节点
delete(element){
var currentNode =this.head;
while(currentNode.next.data!=element){
currentNode = currentNode.next;
}
currentNode.next = currentNode.next.next;
this.size--;
}
}
双向链表的实现
//结点类
class Node{
constructor(data){
this.data = data;//结点的数据域
this.prev = null;//指针域:指向当前结点的上一个结点
this.next = null;//指针域:指向当前结点的下一个结点
}
}
//双向链表类
class DoubleLinkList{
constructor(){
this.size = 0;//双向链表长度
this.head = new Node('head');
this.currNode = '';//当前节点指针
}
//判断链表是否为空
isEmpty(){
return this.size ===0;
}
//获取单链表的长度
getLength(){
return this.size;
}
//显示当前节点
showNode(){
console.log(thi.currNode.data);
}
//顺序遍历链表
displayList(){
let str = '';
let currentNode = this.head;
while(currentNode){//当前结点存在时
str += currentNode.data;
currentNode = currentNode.next;
if(currentNode){
str += '--->';
}
}
return str;
}
//倒序遍历链表
lastDisplayList(){
let str = ''
let currentNode = this.findLast();
while(currentNode){
str += currentNode.data;
currentNode = currentNode.prev;
if(currentNode){
str += '--->';
}
}
return str;
}
//查找某一个元素
findNode(element){
let currentNode = this.head;
while(currentNode && (currentNode.data != element)){
currentNode = currentNode.next;
}
return currentNode;
}
//获取最后一个结点
findLast(){
let currentNode = this.head;
while(currentNode.next){
currentNode = currentNode.next;
}
return currentNode;
}
//添加元素 头插法:在head结点后添加结点
headAppend(element){
let newNode = new Node(element);//创建一个新结点
/* 先让待插入的结点与给定结点之外的结点相连,再与给定结点相连 */
newNode.next = this.head.next;
this.head.next.prev = newNode;
newNode.prev = this.head;
this.head.next = newNode;
this.size++;
}
//添加元素 尾插法
append(element){
let currentNode = this.findLast();
let newNode = new Node(element);
currentNode.next = newNode;
newNode.prev = currentNode;
newNode.next = null;
this.size++;
}
//添加元素 插入结点,将element值插入到data值之后
insertNextNode(data,element){
let currentNode = this.findNode(data);
if(!currentNode){//如果data结点不存在
return;
}
let newNode = new Node(element);
newNode.next = currentNode.next;
currentNode.next.prev = newNode;
newNode.prev = currentNode;
currentNode.next = newNode;
this.size++;
}
//添加元素 插入结点,将element值插入到data值之前
insertpreNode(data,element){
let currentNode = this.findNode(data);
if(!currentNode){
return;
}
let newNode = new Node(element);
newNode.prev = currentNode.prev;
currentNode.prev.next = newNode;
newNode.next = currentNode;
currentNode.prev = newNode;
this.size++;
}
//删除指定节点
deleteNode(element){
let currentNode = this.findNode(element);
if(currentNode.next === null){//要删除的结点为链表的最后一个节点
currentNode.prev.next = null;
}else{
currentNode.prev.next = currentNode.next;
currentNode.next.prev = currentNode.prev;
}
this.size--;
}
}
//创建一个空双向链表
let doubleList = new DoubleLinkList()
//判断链表是否为空
console.log(doubleList.isEmpty()) //true
//尾插法依次插入数组中的元素
let arr = [1,3,5];
for(let i=0;i<arr.length;i++){
doubleList.append(arr[i]);
}
//遍历双向链表
console.log(doubleList.displayList()); //head--->1--->3--->5
//指定结点后插入新结点
doubleList.insertNextNode(3,4); //head--->1--->3--->4--->5
//指定结点前插入新结点
doubleList.insertpreNode(3,2); //head--->1--->2--->3--->4--->5
//删除指定结点
doubleList.deleteNode(5); //head--->1--->2--->3--->4
//前插法 在头元素后插入结点
doubleList.headAppend(100); //head--->100--->1--->2--->3--->4
doubleList.headAppend(20); //head--->20--->100--->1--->2--->3--->4
//倒序遍历
console.log(doubleList.lastDisplayList()); //4--->3--->2--->1--->100--->20--->head