JavaScript数据结构之链表的实现


Posted in Javascript onMarch 19, 2017

前面楼主分别讨论了数据结构栈与队列的实现,当时所用的数据结构都是用的数组来进行实现,但是数组有的时候并不是最佳的数据结构,比如在数组中新增删除元素的时候需要将其他元素进行移动,而在javascript中使用spit()方法不需要访问其他元素。如果你在使用数组的时候发现很慢,就可以考虑使用链表。

链表的概念

链表是一种常见的数据结构。它是动态地进行存储分配的一种结构。链表有一个“头指针”变量,以head表示,它存放一个地址,指向一个元素。每个结点都使用一个对象的引用指标它的后继,指向另一个结点的引用叫做链。

JavaScript数据结构之链表的实现

数组元素依靠下标(位置)来进行引用,而链表元素则是靠相互之间的关系来进行引用。因此链表的插入效率很高,下图演示了链表结点d的插入过程: 

 JavaScript数据结构之链表的实现

删除过程:

JavaScript数据结构之链表的实现

基于对象的链表

我们定义2个类,Node类与LinkedList类,Node为结点数据,LinkedList保存操作链表的方法。

首先看Node类:

function Node(element){
  this.element = element;
   this.next = null;
 }

element用来保存结点上的数据,next用来保存指向一下结点的的链接。

LinkedList类:

function LinkedList(){
     this.head = new Node('head');
     this.find = find;
     this.insert = insert;
     this.remove = remove;
     this.show = show;
}

find()方法,从头结点开始,沿着链表结点一直查找,直到找到与item内容相等的element则返回该结点,没找到则返回空。

function find(item){
     var currentNode = this.head;//从头结点开始
     while(currentNode.element!=item){
         currentNode = currentNode.next;
     }
     return currentNode;//找到返回结点数据,没找到返回null
}

Insert方法。通过前面元素插入的演示可以看出,实现插入简单四步:

1、创建结点

2、找到目标结点

3、修改目标结点的next指向链接

4、将目标结点的next值赋值给要插入的结点的next

function insert(newElement,item){
     var newNode = new Node(newElement);
     var currentNode = this.find(item);
     newNode.next = currentNode.next;
     currentNode.next = newNode;
 }

Remove()方法。删除某一节点需要先找到被删除结点的前结点,为此我们定义方法frontNode():

function frontNode(item){
     var currentNode = this.head;
     while(currentNode.next.element!=item&¤tNode.next!=null){
         currentNode = currentNode.next;
     }   
     return currentNode;
}

简答三步:

1、创建结点

2、找到目标结点的前结点

3、修改前结点的next指向被删除结点的n后一个结点

function remove(item){
     var frontNode = this.frontNode(item);
     //console.log(frontNode.element);
     frontNode.next = frontNode.next.next;
 }

Show()方法:

function show(){
     var currentNode = this.head,result;
     while(currentNode.next!=null){
         result += currentNode.next.element;//为了不显示head结点
         currentNode = currentNode.next;
     }
}

测试程序:

var list = new LinkedList();
list.insert("a","head");
list.insert("b","a");
list.insert("c","b");
console.log(list.show());
list.remove("b");
console.log(list.show());

输出:

JavaScript数据结构之链表的实现

双向链表

从链表的头节点遍历到尾节点很简单,但有的时候,我们需要从后向前遍。此时我们可以通过给 Node 对象增加一个属性,该属性存储指向前驱节点的链接。楼主用下图来双向链表的工作原理。

JavaScript数据结构之链表的实现

首先我们先给Node类增加front属性:

function Node(element){
  this.element = element;
  this.next = null;
   this.front = null;
 }

当然,对应的insert()方法和remove()方法我们也需要做相应的修改: 

function insert(newElement,item){
  var newNode = new Node(newElement);
  var currentNode = this.find(item);
  newNode.next = currentNode.next;
  newNode.front = currentNode;//增加front指向前驱结点
  currentNode.next = newNode;
}
function remove(item){  
  var currentNode = this.find(item);//找到需要删除的节点
  if (currentNode.next != null) {
    currentNode.front.next = currentNode.next;//让前驱节点指向需要删除的节点的下一个节点
    currentNode.next.front = currentNode.front;//让后继节点指向需要删除的节点的上一个节点
    currentNode.next = null;//并设置前驱与后继的指向为空
    currentNode.front = null;    
  }  
}

反序显示链表:

需要给双向链表增加一个方法,用来查找最后的节点。 findLast() 方法找出了链表中的最后一个节点,可以免除从前往后遍历链。

function findLast() {//查找链表的最后一个节点
  var currentNode = this.head;
  while (currentNode.next != null) {
    currentNode = currentNode.next;
  }
  return currentNode;
}

实现反序输出:

function showReverse() {
  var currentNode = this.head, result = "";
  currentNode = this.findLast(); 
  while(currentNode.front!=null){
    result += currentNode.element + " ";
    currentNode = currentNode.front;
  }
  return result;
}

测试程序:

var list = new LinkedList();
list.insert("a","head");
list.insert("b","a");
list.insert("c","b");
console.log(list);
list.remove("b");
console.log(list.show());
console.log(list.showReverse());

输出:

JavaScript数据结构之链表的实现

循环链表

循环链表是另一种形式的链式存贮结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。循环链表和单向链表相似,节点类型都是一样的。唯一的区别是,在创建循环链表时,让其头节点的 next 属性指向它本身,即:

head.next = head

这种行为会传导至链表中的每个节点,使得每个节点的 next 属性都指向链表的头节点。楼主用下图来表示循环链表:

JavaScript数据结构之链表的实现

修改构造方法:

function LinkedList(){
  this.head = new Node('head');//初始化
  this.head.next = this.head;//直接将头节点的next指向头节点形成循环链表
  this.find = find;
  this.frontNode = frontNode;
  this.insert = insert;
  this.remove = remove;
  this.show = show; 
}

这时需要注意链表的输出方法show()与find()方法,原来的方式在循环链表里会陷入死循环,while循环的循环条件需要修改为当循环到头节点时退出循环。

function find(item){
  var currentNode = this.head;//从头结点开始
  while(currentNode.element!=item&¤tNode.next.element!='head'){
    currentNode = currentNode.next;
  }
  return currentNode;//找到返回结点数据,没找到返回null
}
function show(){
  var currentNode = this.head,result = "";
  while (currentNode.next != null && currentNode.next.element != "head") {   
    result += currentNode.next.element + " ";
    currentNode = currentNode.next;
  }
  return result;
}

测试程序:

var list = new LinkedList();
list.insert("a","head");
list.insert("b","a");
list.insert("c","b");
console.log(list.show());
list.remove("b");
console.log(list.show());

测试结果:

JavaScript数据结构之链表的实现

本文用到的示例代码地址:https://github.com/LJunChina/JavaScript

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
灵活应用js调试技巧解决样式问题的步骤分享
Mar 15 Javascript
js绑定事件this指向发生改变的问题解决方法
Apr 23 Javascript
js调用浏览器打印模块实现点击按钮触发自定义函数
Mar 21 Javascript
JavaScript设计模式之装饰者模式介绍
Dec 28 Javascript
微信小程序实现滑动删除效果
May 19 Javascript
vue中component组件的props使用详解
Sep 04 Javascript
基于Vue2.X的路由和钩子函数详解
Feb 09 Javascript
优化Vue项目编译文件大小的方法步骤
May 27 Javascript
使用 webpack 插件自动生成 vue 路由文件的方法
Aug 20 Javascript
vue简单练习 桌面时钟的实现代码实例
Sep 19 Javascript
如何HttpServletRequest文件对象并储存
Aug 14 Javascript
Vue router传递参数并解决刷新页面参数丢失问题
Dec 02 Vue.js
用jQuery实现圆点图片轮播效果
Mar 19 #Javascript
Bootstrap 网格系统布局详解
Mar 19 #Javascript
用JavaScript和jQuery实现瀑布流
Mar 19 #Javascript
JSONP基础知识详解
Mar 19 #Javascript
jQuery中table数据的值拷贝和拆分
Mar 19 #Javascript
js实现旋转木马效果
Mar 17 #Javascript
jQuery实现验证码功能
Mar 17 #Javascript
You might like
微信公众平台天气预报功能开发
2014/07/06 PHP
PHP微信红包生成代码分享
2016/10/06 PHP
laravel-admin的图片删除实例
2019/09/30 PHP
Laravel框架之解决前端显示图片问题
2019/10/24 PHP
CI框架简单分页类用法示例
2020/06/06 PHP
jquery HotKeys轻松搞定键盘事件代码
2008/08/30 Javascript
使用javascipt---实现二分查找法
2013/04/10 Javascript
深入讲解AngularJS中的自定义指令的使用
2015/06/18 Javascript
jQuery实现可移动选项的左右下拉列表示例
2016/12/26 Javascript
JS表格组件神器bootstrap table使用指南详解
2017/04/12 Javascript
MUI 上拉刷新/下拉加载功能实例代码
2017/04/13 Javascript
vue-cli如何引入bootstrap工具的方法
2017/10/19 Javascript
Angular中支持SCSS的方法
2017/11/18 Javascript
详解JavaScript原型与原型链
2020/11/16 Javascript
[02:50]2014DOTA2 TI预选赛预选赛 大神专访第一弹!
2014/05/21 DOTA
[01:45]亚洲邀请赛互动指南虚拟物品介绍
2015/01/30 DOTA
将Django使用的数据库从MySQL迁移到PostgreSQL的教程
2015/04/11 Python
Python语言实现机器学习的K-近邻算法
2015/06/11 Python
Python编写简单的HTML页面合并脚本
2016/07/11 Python
Python中实现switch功能实例解析
2018/01/11 Python
在Python 2.7即将停止支持时,我们为你带来了一份python 3.x迁移指南
2018/01/30 Python
解决seaborn在pycharm中绘图不出图的问题
2018/05/24 Python
python3实现指定目录下文件sha256及文件大小统计
2019/02/25 Python
python中sympy库求常微分方程的用法
2020/04/28 Python
Python实现爬取网页中动态加载的数据
2020/08/17 Python
移动端Html5页面生成图片解决方案
2018/08/07 HTML / CSS
Grow Gorgeous美国官网:只要八天,体验唤醒毛囊后新生的茂密秀发
2018/06/04 全球购物
奥地利体育网上商店:Gigasport
2019/10/09 全球购物
幼儿教师国培感言
2014/02/19 职场文书
化学专业自荐信
2014/05/28 职场文书
新年祝酒词大全
2015/08/11 职场文书
2016教师暑期培训学习心得体会
2016/01/09 职场文书
Go Gin实现文件上传下载的示例代码
2021/04/02 Golang
Windows中Redis安装配置流程并实现远程访问功能
2021/06/07 Redis
MongoDB安装使用并实现Python操作数据库
2021/06/28 MongoDB
Java Socket实现多人聊天系统
2021/07/15 Java/Android