前言
之前在leetcode 刷题看见了一个单向链表的题就简单的复习了一下链表的知识
链表:
- 在内存中可以存在任何地方,不要求连续。
- 每一个数据都保存了下一个数据的内存地址,通过这个地址找到下一个数据。 第一个人知道第二个人的座位号,第二个人知道第三个人的座位号……
- 增加数据和删除数据很容易。 再来个人可以随便坐,比如来了个人要做到第三个位置,那他只需要把自己的位置告诉第二个人,然后问第二个人拿到原来第三个人的位置就行了。其他人都不用动。
- 查找数据时效率低,因为不具有随机访问性,所以访问某个位置的数据都要从第一个数据开始访问,然后根据第一个数据保存的下一个数据的地址找到第二个数据,以此类推。 要找到第三个人,必须从第一个人开始问起。
- 不指定大小,扩展方便。链表大小不用定义,数据随意增删。
- 以上有关于链表的叙述来源于其他文章。
设计
我设计的链表只有一个类,该类里面有两个属性 分别问 head 和length 以及其他内部方法
head:用来保存链表的头节点
length:用来存储当前链表的长度
function LinkedList(){
//辅助类:表示要加入链表的项
let Node = function(element){
this.element = element;
this.next = null;//这个节点的下一个节点暂时为空
}
this.length = 0;
this.head = null;
this.append = function(element){ };//向链表的尾部添加节点
this.insert = function(position,element){};//在指定的位置添加节点
this.remove = function(ele){};//将指定的节点删除掉
this.removeAt = function(position){};//将指定位置的节点删除
this.searchElement = function(element){};//查找指定元素的位置
this.searchPosition = function(position){};//查找指定位置的元素
this.display = function(){
var currNode = this.head;
while ( !(currNode.next == null) ){
console.log( currNode.next.element );
currNode = currNode.next;
}
}
}
Node 用来构建一个链表的某个节点, elemen 该节点的值,next 为指向下一节点的指针。
append:向链表的末尾添加一个节点
this.append = function(element){
if(this.head=== null){
this.head = new Node(element);
this.length++;
}
else{
let c =this.head;
let n = new Node(element);
while(c.next){
c=c.next
}
c.next = n;
this.length++;
}
};//向链表的尾部添加节点
首先判断head是否为null 如果为空 代表该链表没有元素,所以先初始化一个节点赋值给this.head 该节点的值为传入的elment
如果不为空代表链表有一个以上的节点,还是先构建一个节点,然后将这个节点添加到链表末尾。
由于链表不具有随机访问属性,无法通过下标访问 所以要从 链表头部遍历,直到便利到某个节点的next值为null时候,这就找到了链表的尾部,尾部.next=new Node(element),这样就完成了向链表末尾添加了一个新节点。
insert:向链表的某个位置插入一个新节点
this.insert = function(position,element){
if(position>=0 &&position<=this.length){
let node = new Node(element);
let c = this.head;
let b;
if(position==0){
node.next=this.head;
this.head = node
}
else{
for(let i = 0 ;i<position ;i++){
b= c;
c=c.next;
// console.log(c);
}
b.next=node;
node.next=c;
}
this.length++;
}
};//在指定的位置添加节点
首先判断传入的position 是否在该链表范围内 , 然后 利用一重for循环 将b指针指向 目标节点的前一个节点,将c指向目标节点,将b.next的值改成新的节点node,将node.next的值改成c。这样就完成了链表的指定位置插入。
remove:将指定的节点删除掉
this.removeAt = function(position){
if(position>=0&&position<=this.length){
if(position===0){
this.head=this.head.next;
this.length--;
}
else{
let i=1,b;
var c =this.head
while(i<position){
i++;
b=c;
c=c.next;
}
console.log(b,c)
b.next=c.next;
this.length--;
}
}
};//将指定位置的节点删除
删除指定节点原理和添加节点一样,很简单就是改变目标位置前一个节点的指针指向。不多叙述。
display:输出链表
this.display = function(){
var currNode = this.head;
while ( !(currNode.next == null) ){
console.log( currNode.next.element );
currNode = currNode.next;
}
}
}
在前端开发工作中很少会用到链表的这种数据结构,但是在投简历面试的时候,可能面试官会问如何用js 实现链表或者栈的操作,其实并不复杂以下是完整代码。
function LinkedList(){
//辅助类:表示要加入链表的项
let Node = function(element){
this.element = element;
this.next = null;//这个节点的下一个节点暂时为空
}
this.length = 0;
this.head = null;
this.append = function(element){
if(this.head=== null){
this.head = new Node(element);
this.length++;
}
else{
let c =this.head;
let n = new Node(element);
while(c.next){
c=c.next
}
c.next = n;
this.length++;
}
};//向链表的尾部添加节点
this.insert = function(position,element){
if(position>=0 &&position<=this.length){
let node = new Node(element);
let c = this.head;
let b;
if(position==0){
node.next=this.head;
this.head = node
}
else{
for(let i = 0 ;i<position ;i++){
b= c;
c=c.next;
// console.log(c);
}
b.next=node;
node.next=c;
}
this.length++;
}
};//在指定的位置添加节点
this.remove = function(ele){
let c = this.head;
while(c.next.element!=ele){
c=c.next;
}
c.next=c.next.next;
this.length--;
};//将指定的节点删除掉
this.removeAt = function(position){
if(position>=0&&position<=this.length){
if(position===0){
this.head=this.head.next;
this.length--;
}
else{
let i=1,b;
var c =this.head
while(i<position){
i++;
b=c;
c=c.next;
}
console.log(b,c)
b.next=c.next;
this.length--;
}
}
};//将指定位置的节点删除
this.searchElement = function(element){};//查找指定元素的位置
this.searchPosition = function(position){};//查找指定位置的元素
this.display = function(){
var currNode = this.head;
while ( !(currNode.next == null) ){
console.log( currNode.next.element );
currNode = currNode.next;
}
}
}
let p = new LinkedList();
p.append(0);
p.append(1);
p.append(2);
p.append(3);
p.append(4);
p.append(5);
p.append(6);
// p.insert(3,'xxxx');
p.removeAt(3);
console.log(p.display())
总而言之,链表这一数据结构和数组的差别还是挺大的,属于两种不同的思维方式。以上代码中还包含了一个简单浅拷贝原理,会在下篇文章中叙述。新人求关照。