JavaScript数据结构之链表

链表是数据结构中最简单也是最常提及的一种数据结构了,不同于数组,在链表里面所有的结点数据内存都是不连续的,这就要求在访问链表的时候只能从头一个一个去访问,同时正是由于这个特性,链表可以动态分配内存空间,在性能上,链表远胜数组,这也是为什么在处理大型数据的时候,大多数都使用链表而不是数组。

接下来我将介绍几种链表常用方法,概念不多介绍,直接上代码!

*文章最后附源码

一、初始化准备阶段

function LinkList()
{
    this.head=null; //初始化头结点为空

    //内部类,储存结点数据和next
	function Node(data){
		this.data=data;
		this.next=null;
	}

}

需要注意:本链表是不带头结点的,在后续插入删除等操作可能会与带头结点的链表稍有区别

在LinkList构造函数中包含了一个构造函数,称之为“内部类”,这个类主要保存每个结点的数据域(data)和指针域(next),后续的创建新结点都会new 这个构造函数

二、插入结点——头插法

//头插法
LinkList.prototype.insertListByHead=function(data){
	const node=new Node(data); //实例化新结点

	//第一个插入的结点让头结点指向该结点
	if(!this.head){
		this.head=node;
		return;
	}

	//头插法关键代码
	node.next=this.head;
	this.head=node;
}

三、插入结点——尾插法

//尾插法
LinkList.prototype.insertListByTail=function(data){
	const node=new Node(data);

	if(!this.head){
		this.head=node;
		return;
	}

	//尾插法关键代码
	let p=this.head;
	while(p.next){
		p=p.next;
	}
	p.next=node;
}

四、插入——指定位置插入

//指定位置插入
LinkList.prototype.insertListByPos=function(data,Pos){
	const node=new Node(data);

	//如果插入的位置是第一个,直接调用一次头插法
	if (Pos === 1) {
		this.insertListByHead(data);
		return;
	}

	//链表为空,直接插入head,忽略Pos
	if(!this.head){
		this.head=node;
		return;
	}

	let p=this.head;
	let i=0; //位置索引
	for(;p.next;p=p.next){
		i++;
		if(i===Pos-1){
			node.next=p.next;
			p.next=node;
			return;
		}
	}

	//当输入的Pos大于链表总长,直接插入到最后
	p.next=node;
}

五、修改结点值

//修改指定位置的值
LinkList.prototype.updateData=function(newData,Pos){
	if(!this.head){
		console.log(new Error('链表为空,无需更新'));
		return false;
	}

	let i=0;
	let p=this.head;
	while(p){
		if(i===Pos-1){
			p.data=newData;
			break;
		}
		i++;
		p=p.next;
	}

	if(!p){
		console.log(new Error('未找到该位置'));
	}
}

六、获取结点

//获取指定位置结点
LinkList.prototype.getData=function(Pos){
	if(!this.head){
		console.log(new Error('链表为空'));
		return;
	}

	let i=0;
	let p=this.head;
	while( i++ < Pos && p){
		if(i===Pos){
			return p.data;
		}
		p=p.next;
	}

	console.log(new Error('未找到该位置'));
}

七、删除结点

//按指定位置删除结点
LinkList.prototype.deleteData=function(Pos){
	if(!this.head){
		console.log(new Error('链表为空'));
		return;
	}

	let p=this.head;
	let i=1;
	//如果删除的是头结点
	if(Pos===1){
		p=p.next;
		this.head=p;
		return;	
	}
	while(p.next){
		if(i===Pos-1){
			let r=p.next;
			p.next=r.next;
			return;
		}
		i++;
		p=p.next;
	}

	console.log(new Error('未找到该位置'));
}

八、清空链表

//清空链表
LinkList.prototype.clear=function(){
	let q=null;
	while(this.head){
		q=this.head.next;
		this.head=null;
		this.head=q;
	}
}

附:完整源码:

'use strict'
function LinkList(){
	//初始化头结点为null
	this.head=null;
	//内部类,储存结点数据和next
	function Node(data){
		this.data=data;
		this.next=null;
	}

	//头插法
	LinkList.prototype.insertListByHead=function(data){
		const node=new Node(data);

		//第一个插入的结点让头结点指向该结点
		if(!this.head){
			this.head=node;
			return;
		}

		//头插法关键代码
		node.next=this.head;
		this.head=node;
	}

	//尾插法
	LinkList.prototype.insertListByTail=function(data){
		const node=new Node(data);

		if(!this.head){
			this.head=node;
			return;
		}

		//尾插法关键代码
		let p=this.head;
		while(p.next){
			p=p.next;
		}
		p.next=node;
	}

	//指定位置插入
	LinkList.prototype.insertListByPos=function(data,Pos){
		const node=new Node(data);

		//如果插入的位置是第一个,直接调用一次头插法
		if (Pos === 1) {
			this.insertListByHead(data);
			return;
		}

		//链表为空,直接插入head,忽略Pos
		if(!this.head){
			this.head=node;
			return;
		}

		let p=this.head;
		let i=0; //位置索引
		for(;p.next;p=p.next){
			i++;
			if(i===Pos-1){
				node.next=p.next;
				p.next=node;
				return;
			}
		}

		//当输入的Pos大于链表总长,直接插入到最后
		p.next=node;
	}

	//修改指定位置的值
	LinkList.prototype.updateData=function(newData,Pos){
		if(!this.head){
			console.log(new Error('链表为空,无需更新'));
			return false;
		}

		let i=0;
		let p=this.head;
		while(p){
			if(i===Pos-1){
				p.data=newData;
				break;
			}
			i++;
			p=p.next;
		}

		if(!p){
			console.log(new Error('未找到该位置'));
		}
	}

	//获取指定位置结点
	LinkList.prototype.getData=function(Pos){
		if(!this.head){
			console.log(new Error('链表为空'));
			return;
		}

		let i=0;
		let p=this.head;
		while( i++ < Pos && p){
			if(i===Pos){
				return p.data;
			}
			p=p.next;
		}

		console.log(new Error('未找到该位置'));
	}

	//按指定位置删除结点
	LinkList.prototype.deleteData=function(Pos){
		if(!this.head){
			console.log(new Error('链表为空'));
			return;
		}

		let p=this.head;
		let i=1;
		//如果删除的是头结点
		if(Pos===1){
			p=p.next;
			this.head=p;
			return;	
		}
		while(p.next){
			if(i===Pos-1){
				let r=p.next;
				p.next=r.next;
				return;
			}
			i++;
			p=p.next;
		}

		console.log(new Error('未找到该位置'));
	}

	//清空链表
	LinkList.prototype.clear=function(){
		let q=null;
		while(this.head){
			q=this.head.next;
			this.head=null;
			this.head=q;
		}
	}
}

const linkList=new LinkList();
linkList.insertListByHead(1);
linkList.insertListByHead(2);
linkList.insertListByHead(3);
linkList.insertListByPos(4,1);
console.log(linkList);

const linkList2=new LinkList();
linkList2.insertListByHead(1);
linkList2.insertListByHead(2);
linkList2.insertListByHead(3);
// linkList2.deleteData(3);
// linkList2.deleteData(2);
// linkList2.deleteData(3);
linkList2.clear();
console.log(linkList2);

源码已经附上,大家可以上机练练手

如果发现有什么不足或建议,欢迎留言!

创作不易,点个赞好不好?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值