链表是一种动态的数据结构,下面说说数组和链表间的对比:
- 数组由于可以通过下标查找对应的元素,所以查询方便,但是对于插入和删除操作,需要遍历,所以消耗比较大
- 链表的特点与数组相反,它由于不是顺序存储,所以插入和删除都比较方便,但是查询某个元素就比较麻烦,需要从头开始遍历
1)链表的特点:
- 存储位置不连续
- 每个元素由存储本身的节点和一个指向下一个元素的引用组成
2)链表的实例:
- 寻宝游戏
3)基本骨架:
function LinkedList(){
let Node=function(element){ //链表的元素
this.element=element;//元素的内容
this.next=null;//指向下一个的指针
};
let length=0;
let head=null;//头指针
this.append=function(element){};//向尾部添加一个新的项
this.insert=function(position,element){};//向链表特定位置插入一个新的项
this.removeAt=function(position){};//移除特定位置的项
this.remove=function(element){};//移除一项
this.indexOf=function(element){};//返回元素在列表中的索引,没有返回-1
this.isEmpty=function(){};//链表中不含任何元素,则返回true,否则,返回false
this.size=function(){};//返回包含的元素个数
this.getHead=function(){};//返回头指针
this.toString=function(){};//输出链表中的内容
this.print=function(){};
}
4)具体实现
增:
a.向链表尾部追加元素
this.append=function(element){
let node=new Node(element),//现将元素转为节点的形式
current;//用于存放当前头指针
if(head===null){
head=node;//如果为空,则直接将该元素赋值给头指针
}else{
current=head;//如果不为空,将头指针保存在current变量
while(current.next){
current=current.next;//循环列表,直到最后一项
}
current.next=node;//找到最后一项,将其next赋值为node,建立连接
}
length++;//更新链表的长度
};//向尾部添加一个新的项
b.在任意位置插入元素
this.insert=function(position,element){
if(position>=0&&position<=length){
let node=new Node(element),
current=head,
previous,
index;
if(position===0){
node.next=current;
head=node;
}else{
while(index++<position){
previous=current;
current=current.next;
}
node.next=current;
previous.next=node;
}
length++;//更新列表长度
return true;
}else{
return false;
}
};//向链表特定位置插入一个新的项
删:
a.从链表中移除元素
this.removeAt=function(position){
//检查越界值
if(position>-1&&position<length){
let current=head,//指向第一个元素
previous,
index=0;
//移除第一项
if(position===0){
head=current.next;//将第二个元素赋值给头指针
}else{
while(index++<position){
previous=current;
current=current.next;
}
previous.next=current.next;//将previous与current的下一项连接起来,跳过current,从而实现移除
}
length--;
return current.element;
}else{
return null;//如果越界,则返回null;
}
};//移除特定位置的项
b.remove方法
this.remove=function(element){
let index=this.indexOf(element);
return this.removeAt(index);
};//移除一项
其他:
toString方法
this.toString=function(){
let current=head,
string='';
while(current){
string+=current.element+(current.next?'n':'');
current=current.next;
}
return string;
};//输出链表中的内容
indexOf方法:
this.indexOf=function(element){
let current=head,
index=-1;
while(current){
if(element===current.element){
return index;
}
index++;
current=current.next;
}
return -1;
};//返回元素在列表中的索引,没有返回-1
isEmpty方法:
this.isEmpty=function(){
return length==0;
};//链表中不含任何元素,则返回true,否则,返回false
size方法:
this.size=function(){
return length;
};//返回包含的元素个数
getHead方法:
this.getHead=function(){
return head;
};//返回头指针
完整功能实现代码:
function LinkedList(){
let Node=function(element){ //链表的元素
this.element=element;//元素的内容
this.next=null;//指向下一个的指针
};
let length=0;
let head=null;//头指针
this.append=function(element){
let node=new Node(element),//现将元素转为节点的形式
current;//用于存放当前头指针
if(head===null){
head=node;//如果为空,则直接将该元素赋值给头指针
}else{
current=head;//如果不为空,将头指针保存在current变量
while(current.next){
current=current.next;//循环列表,直到最后一项
}
current.next=node;//找到最后一项,将其next赋值为node,建立连接
}
length++;//更新链表的长度
};//向尾部添加一个新的项
this.insert=function(position,element){
if(position>=0&&position<=length){
let node=new Node(element),
current=head,
previous,
index;
if(position===0){
node.next=current;
head=node;
}else{
while(index++<position){
previous=current;
current=current.next;
}
node.next=current;
previous.next=node;
}
length++;//更新列表长度
return true;
}else{
return false;
}
};//向链表特定位置插入一个新的项
this.removeAt=function(position){
//检查越界值
if(position>-1&&position<length){
let current=head,//指向第一个元素
previous,
index=0;
//移除第一项
if(position===0){
head=current.next;//将第二个元素赋值给头指针
}else{
while(index++<position){
previous=current;
current=current.next;
}
previous.next=current.next;//将previous与current的下一项连接起来,跳过current,从而实现移除
}
length--;
return current.element;
}else{
return null;//如果越界,则返回null;
}
};//移除特定位置的项
this.remove=function(element){
let index=this.indexOf(element);
return this.removeAt(index);
};//移除一项
this.indexOf=function(element){
let current=head,
index=-1;
while(current){
if(element===current.element){
return index;
}
index++;
current=current.next;
}
return -1;
};//返回元素在列表中的索引,没有返回-1
this.isEmpty=function(){
return length==0;
};//链表中不含任何元素,则返回true,否则,返回false
this.size=function(){
return length;
};//返回包含的元素个数
this.getHead=function(){
return head;
};//返回头指针
this.toString=function(){
let current=head,
string='';
while(current){
string+=current.element+(current.next?'n':'');
current=current.next;
}
return string;
};//输出链表中的内容
}
链表进阶:
- 双向链表
- 特点:在双向链表中,链接是双向的:一个链向下一个元素,另一个链向前一个元素,这样就提供了两种迭代列表的方法:从头到尾或者从尾到头。
- 实现的方法:
1)基本骨架:
function DoublyLinkedList(){
let Node=function(element){
this.element=element;
this.next=null;//头指针
this.prev=null;//尾指针
}
let length=0;
let head=null;
let tail=null;
}
2)任意位置插入元素
this.insert=function(position,element){
//检查越界值
if(position>=0&&position<=length){
let node=new Node(element),
current=head,
previous,
index=0;
if(position===0){ //在第一个位置插入元素
if(!head){ //没有元素时,头尾指针均指向node
head=node;
tail=node;
}else{
node.next=current;
current.prev=node;
node.prev=current;
tail=node;
}
}else if(position===length){
current=tail;//让当前项为尾指针指向的项,这就体现了双向链表的作用
current.next=node;
node.prev=current;
tail=node;
}else{
while(index++<position){
previous=current;
current=current.next;
}
node.next=current;
previous.next=node;
current.prev=node;
node.prev=previous;
}
length++;
return true;
}else{//越界
return false;
}
}
3)从任意位置移除元素
this.removeAt=function(position){
if(position>-1&&position<length){
let current=head,
previous,
index=0;
//移除第一项
if(position===0){
head=current.next;
if(length===1){
tail=null;//如果只有一项,更新tail
}else{
head.prev=null;//将新加入的第一项元素的prev指针设置为空
}
}else if(position===length-1){
current=tail;
tail=current.prev;
tail.next=null;
}else{
while(index++<position){
previous=current;
current=current.next;
}
previous.next=current.next;
current.next.prev=previous;
}
length--;
return current.element;
}else{
return null;//越界处理
}
}
- 循环列表
- 特点:最后一个元素的指向下一个元素的指针指向第一个元素