面向前端的算法——链表结构

221 阅读3分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

不是按传统教科书,或视频讲数据结构,而是贴合我们实际前端开发讲的,也是我工作当中总结的,仅做参考,很多地方可能与书上不一样。反正仅做参考

1. 前端js构建链表结构

1.1 单向链表结构

这里我按书上标准的,复制粘贴:线性表的链式存储,指通过任意的存储单元来存储线性表中的数据元素。 为了建立数据元素的线性关系,每一个链表的结点除了存放元素的自身信息之外,还需要存放一个指向其后继的指针。

是不是比较生涩难懂,告诉你,前端最简单的表示方法就是这样的:

const a = {
	data:'A'
	next:{
		data:'B',
		next:{
			data:'C',
			next:{
				data:'D',
				next:null
			}
		}
	}
} 

完全遵循a.next.next.next.next,只是少了一些方法,正好这些方法就可以锻炼我们的算法思维能力。从上面,我们可以清楚的明白链表结构只能从表头(上面例子就是a)存取元素

1.2 给一个对象扩展成一个链表结构

const linksListHead = {data:'A',next:null}
const linkNodeArray = [{data:'B',next:null},{data:'C',next:null},{data:'D',next:null}]

如何将linksListHead使用linkNodeArray的数据变成一个链表?

头插法

const linksListHead = {data:'A',next:null}
const linkNodeArray = [{data:'B',next:null},{data:'C',next:null},{data:'D',next:null}]
function generateLinkedList(linkhd,dataArray){
	let L = linkhd
	dataArray.forEach( item =>{
		L.next = item;
		L = item
	})
	return linkhd
}
const linkedListA = generateLinkedList(linksListHead,linkNodeArray)
console.log( linkedListA )

尾插法 也就是給一个链表结构的尾部节点进行插入操作,还是以上面的数据为基础,尾插法代码如下:

const linksListFoot = {data:'D',next:null}
const linkNodeArray = [{data:'C',next:null},{data:'B',next:null},{data:'A',next:null}]
function generateLinkedList(linkft,dataArray){
	let L = linkft
	dataArray.forEach( item =>{
		item.next = L
		L = item
	})
	return L
}
const linkedListA = generateLinkedList(linksListFoot,linkNodeArray)
console.log( linkedListA )

1.3 删除节点操作

按索引号删除 这里的链表数据就用前面生成的链表数据为基础,我们来进行链表的删除操作。

删除链表节点,重要的就是要找到被删除节点的前驱(前驱.next -> 后继)。为此我们有如下代码:

function deletLinkNodeByIndex(linkedList,index){
	let i = 0;
	let linkNode = linkedList;
	if(index-1 < -1){
		console.error(不能删除头结点元素)
	}
	while(i<index-1){
		linkNode = linkNode.next;
		i++
	}
	// 前驱节点
	const preNode = linkNode;
	// 要被删除的节点,也就是前驱的后继节点
	let deletNode = preNode.next;
	// 被删除的节点的后继节点替代他
	const deletNodeNext = deletNode.next;
	preNode.next = deletNodeNext;
	deletNode = null // 释放节点删除
}
deletLinkNodeByIndex(linkedListA,2)
console.log(linkedListA)

按值删除 思路其实和上面差不多,就是按值删除要遍历整个链表,找到要删除的值的节点,然后去找他的前驱,接着找他的后继

1.4 求表长

基本思路就是,从头节点开始使用next循环,当.next的值为null的时候,遍历结束,看一共循环了多少次即可。

2.1 其他扩展

  1. 循环链表,根据上面我说的,其实在前端js领域,你头的next指向尾节点对象就好了
  2. 双向链表,加一个pre,回指就行

小测验 有一个带头的双向循环链表L,节点的结构为{prev,data,next},其中prev和next分别是指向其直接前驱和直接后继节点的指针。现在要删除指针p所指的节点,请问如何删除?