【JS】数据结构之链表

前言

  • 线性表:指的是0个或者多个数据元素有限序列;
  • 他的物理的存储结构有两种:
1. 顺序存储
:用一段连续的存储单元依次存储线性表的数据元素
2. 链式存储
:内存地址可以是连续的,也可以是不连续的,把数据元素存放在任意的存储单元里,指针来存放数据元素的地址

链表

回顾数组:

  • 数组的创建通常需要申请一段连续的内存空间(一整块内存),并且大小是固定的
  • 但是js数组并不是真正意义是的数组,它不是存在一段连续的内存中
  1. 查询修改:数组性能好
比如:int array[4]
假设它占用了从1201位置开始存储区域
当我尝试读array[2]的时候,它只要简单的计算就可以得出array[2]的位置
1201+ (2*4) = 1209 // 4表示一个int 4 个字节
  1. 插入删除:数组性能低
向数组开头或中间位置插入数据的时候,需要重新申请内存,进行大量元素的位移,所以性能很低。

那有没有一种数据结构,能够快速的实现插入和删除?这是就要提到链表了

在这里插入图片描述

  • 链表重点在于元素在内存中不必是连续的空间

  • 链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用,俗称指针

  • 链表的特点

1. 链表没有大小限制,支持动态扩容,因为链表的每个节点第需要存储前驱、后驱节点的指针。
2. 缺点就是内存消耗会翻倍
  • js 实现一个普通链表结构:
// 节点类
class Node {
	constructor(element){
		this.element = element;
		this.next = null;
	}
}
// 链表
class LinkedList {
	constructor(element){
		// 链表头
		this.head = null;
		// 链表长度
		this.length = 0;
		this.element = element;
		this.next = null;
	}
	// 1. 链表的尾部追加元素
	append(element){
		// 创建节点
		let node = new Node(element);
		// 如果链表是空的
		if(this.length === 0){
			// 指向第一个节点
			this.head = node;
		}else{
			// 通过head找到后面的节点
			let current = this.head;
			// 遍历是否是最后一个节点,next为空就是最后一个节点
			while(current.next){
				current = current.next;
			}
			// while 执行完毕后,current就已经是最后一个节点了
			current.next = node;
		}
		// length 长度加 1
		this.length += 1;
	}
	// 2. 获取链表的头
	getHead(){
		return this.head;
	}
	// 3. toString方法
	toSting(){
		let current = this.head;
		let linkSting = '';
		while(current){
			linkSting += ','+current.element;
			current = current.next;
		}
		// 返回的最终结果 [,a,] 从第一个位置开始
		return linkSting.slice(1)
	}
	// 在任意位置插入元素
	insert(element,position){
		// 位置不能是负数
		if(position<0 || position >this.length){
			return false;
		}
		// postion > 1
		let index = 0;
		let current = this.head;
		// 上一个节点
		let privious = null;
		// 创建元素
		let node = new Node(element)
		// 判断插入的是不是第一个
		if(position === 0){
			// 新结点next指向原来的head节点
			node.next = this.head;
			this.head = node;
		}else{
			while(index<position){
				privious = current;
				current = current.next;
				index++;
			}
			node.next = current;
			privious.next = node;
		}
		this.length += 1;
		return true
	}
	// 获取对应位置的元素
	get(position){
		// 越界判断
		if(position<0 || position >this.length){
			return null;
		}
		// 获取对应的节点
		let current = this.head;
		let index = 0;
		while(index<position){
			current = current.next;
			index++;
		}
		return current.element;
	}
	// 根据元素位置删除节点
	removeAt(position){
		if(position<0 || position >this.length){
			return null;
		}
		// 定义一个变量,保存信息
		let index = 0;
		let current = this.head;
		let pribious = null;
		// 判断删除的是否是第一个节点
		if(position === 0){
			this.head = this.head.next;
		}else{
			while(index<position){
				privious = current;
				current = curent.next;
				index++;
			}
			privious.next = current.next;
		}
		this.length -= 1;
		// 返回移除的元素
		return current.element;
	}
	
}

const linkedList = new LinkedList()
linkedList.append('a')
linkedList.append('b')
linkedList.append('c')
console.log(linkedList.get(0))
linkedList.insert('d', 3)
console.log(linkedList.toSting())
console.log(linkedList)
  • 运行结果:
    在这里插入图片描述

链表还有一种双向链表,双向链表和普通链表的区别在于:

  • 在链表中,一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的:一个链向下一个元素,另一个链向前一个元素

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一颗不甘坠落的流星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值