JS中数据结构之链表

 


1、链表的基本介绍

数组不总是组织数据的最佳数据结构,在很多编程语言中,数组的长度是固定的,所以当数组已被数据填满时,再要加入新的元素就会非常困难。在数组中,添加和删除元素也很麻烦,因为需要将数组中的其他元素向前或向后平移。

链表是由一组节点组成的集合。每个节点都使用一个对象的引用指向它的后继。许多链表的实现都在链表最前面有一个特殊节点,叫做头节点。如下图:

2、链表的实现

2.1、基于对象的链表的实现

Node 类用来表示节点,包含两个属性:element 用来保存节点上的数据,next 用来保存指向下一个节点的链接。

  1. function Node(element) {
  2.   this.element = element;
  3.   this.next = null;
  4. }

LList 类提供了对链表进行操作的方法。该类的功能包括插入删除节点、在列表中查找给定的值。

复制代码
  1. function LList() {
  2.   this.head = new Node("head");
  3.   this.find = find;
  4.   this.insert = insert;
  5.   this.display = display;
  6.   this.findPrevious = findPrevious;
  7.   this.remove = remove;
  8. }
复制代码

find() 方法遍历链表,查找给定数据。如果找到数据,该方法就返回保存该数据的节点。如果查找成功,该方法返回包含该数据的节点;否则,返回 null。

复制代码
  1. function find(item) {
  2.   var currNode = this.head;
  3.   while (currNode.element != item) {
  4.     currNode = currNode.next;
  5.   }
  6.   return currNode;
  7. }
复制代码

insert() 方法在一个已知节点后面插入元素

复制代码
  1. function insert(newElement, item) {
  2.   var newNode = new Node(newElement);
  3.   var current = this.find(item);
  4.   newNode.next = current.next;
  5.   current.next = newNode;
  6. }
复制代码

display() 方法用来显示链表中的元素

复制代码
  1. function display() {
  2.   var currNode = this.head;
  3.   while (!(currNode.next == null)) {
  4.     print(currNode.next.element);
  5.     currNode = currNode.next;
  6.   }
  7. }
复制代码

 findPrevious() 方法找到待删除节点前面的节点。找到这个节点后,修改它的 next 属性,使其不再指向待删除节点,而是指向待删除节点的下一个节点。

复制代码
  1. function findPrevious(item) {
  2.   var currNode = this.head;
  3.   while (!(currNode.next == null) && (currNode.next.element != item)) {
  4.     currNode = currNode.next;
  5.   }
  6.   return currNode;
  7. }
复制代码

remove() 方法从链表中删除节点。

复制代码
  1. function remove(item) {
  2.   var prevNode = this.findPrevious(item);
  3.   if (!(prevNode.next == null)) {
  4.     prevNode.next = prevNode.next.next;
  5.   }
  6. }
复制代码

 

2.2、双向链表

给 Node 对象增加一个属性,该属性存储指向前驱节点的链接,这使得链表从后向前遍历变得简单

  1. function Node(element) {
  2.   this.element = element;
  3.   this.next = null;
  4.   this.previous = null;
  5. }

insert() 方法

复制代码
  1. function insert(newElement, item) {
  2.   var newNode = new Node(newElement);
  3.   var current = this.find(item);
  4.   newNode.next = current.next;
      current.next.previous = newNode;
  5.   newNode.previous = current;
  6.   current.next = newNode;
  7. }
复制代码

remove() 方法比单向链表的效率更高,因为不需要再查找前驱节点。

复制代码
  1. function remove(item) {
  2.   var currNode = this.find(item);
  3.   if (!(currNode.next == null)) {
  4.     currNode.previous.next = currNode.next;
  5.     currNode.next.previous = currNode.previous;
  6.     currNode.next = null;
  7.     currNode.previous = null;
  8.   }else {
  9.     currNode.previous.next = null;
  10.     currNode.next = null;
  11.     currNode.previous = null;
  12.   }
  13. }
复制代码

findLast() 方法查找链表中的最后一个节点,避免了从前往后遍历链表

复制代码
  1. function findLast() {
  2.   var currNode = this.head;
  3.   while (!(currNode.next == null)) {
  4.     currNode = currNode.next;
  5.   }
  6.   return currNode;
  7. }
复制代码

dispReverse() 方法反序显示双向链表中的元素。

复制代码
  1. function dispReverse() {
  2.   var currNode = this.head;
  3.   currNode = this.findLast();
  4.   while (!(currNode.previous == null)) {
  5.     console.log(currNode.element);
  6.     currNode = currNode.previous;
  7.   }
  8. }
复制代码

 

2.3、循环链表

循环链表和单向链表相似,节点类型都是一样的。唯一的区别是,在创建循环链表时,让其头节点的 next 属性指向它本身,即链表的尾节点指向头节点,形成了一个循环链表。如下图:

posted @   wenxuehai  阅读(2685)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
//右下角添加目录
点击右上角即可分享
微信分享提示