JavaScript--数据结构算法之链表
数组的缺点:数组的长度固定,增删时比较困难要移动元素,而且数据填满再添加元素比较复杂。
js:数组有split(),可以任意的分割。不存在上述问题。
主要问题是:js数组都被实现成了对象,和其他语言的数组比较而言效率低。
一.单向链表:
有一组节点组成的集合,每一个节点都使用一个对象的引用指向它的后继。指向另一个节点的引用叫做链。
插入元素:只需修改前驱节点,使其指向新的节点,而新加入的节点指向原来前去指向的节点。
删除元素:将待删除元素的前驱节点指向待删除元素的后继节点。
插入,删除性能更高。
设计原理:
包含两个类:Node表示节点,LinkList类提供插入,删除,显示链表元素等方法,以及一些辅助方法。
~(function() {//创建节点,设置两个属性
function Node(ele) {
this.ele = ele;
this.next = null;//初始化时null,当有新元素插入时,next会指向新的元素。
}
function LinkList() {
this.head = new Node("head");//使用Node对象保存改链表的头节点
/!*this.find = find;
this.insert = insert;
this.remove = remove;
this.display = display;*!/
}
LinkList.prototype.find = function () {};//查找指定的元素,遍历链表
LinkList.prototype.insert = function () {};
LinkList.prototype.remove = function () {};
LinkList.prototype.findPrevious = function () {};
LinkList.prototype.display = function () {};//显示链表的元素
/!*1.插入元素:insert();向链表中插入一个节点。
在已知一个节点在后面插入元素时,首先要找到后面的节点,创建一个find()方法遍历链表查找节点。
*!/
LinkList.prototype.find =function (item) {
var currNode = this.head;
while(currNode.ele != item) {
currNode = currNode.next;
}
return currNode;
};//在链表上的移动,创建一个新节点,将链表的头节点赋给新创建的节点,然后在链表上循环当前的ele属性是否与item相当,否则当前结点移动到下一个节点,成功返回,否则null。
LinkList.prototype.insert = function (newEle,item) {
var newNode = new Node(newEle);
var current = this.find(item);
newNode.next = current.next;
current.next = newNode;
};//找到后面的元素,插入链表,将新节点的next属性设置为后面节点的next对应值。然后设置后面节点的next属性指向新的节点。
LinkList.prototype.display = function () {
var currNode = this.head;//变量记录头节点
while(!(currNode.next == null)) {//当前节点不为空遍历链表
console.log(currNode.next.ele);
currNode = currNode.next;//指向下一个节点
}
};
var cities = new LinkList();
cities.insert("BeiJing","head");
cities.insert("ShangHai","BeiJing");
cities.insert("ShenZhen","ShangHai");
cities.insert("GuangZhou","ShenZhen");
cities.insert("ChengDou","GuangZhou");
cities.display();
console.log("===================");
/!*2.删除元素:remove();向链表中删除一个节点。
* 删除节点时:需要找到待删除节点的前驱。只需修改他的后继next指向待删除的下一个节点。定义一个findPrevious()方法。遍历链表的节点,检查每一个节点的下一个节点是否存储这待删除的数据,如果有,返回该节点的前驱。
* *!/
LinkList.prototype.findPrevious = function (item) {
var currNode = this.head;
while(!(currNode.next == null) && (currNode.next.ele != item )) {//当前节点的后继不为空或者后继节点不为所要查找的元素时
currNode = currNode.next;//修改后继链
}
return currNode;//找到时返回
};
LinkList.prototype.remove = function(item) {
var prevNode = this.findPrevious(item);//找到删除元素的前一个元素
if(!(prevNode.next == null)) {//待删除元素不为空
prevNode.next = prevNode.next.next;//待删除元素的前驱的后继修改为待删除元素的后继的后继
}
};
cities.remove("GuangZhou");
cities.display();
console.log("===================");
})();
二.双向链表
通过给Node节点添加一个前驱属性previous,指向前驱节点的链接。但插入时需要指明正确的前驱和后继。删除时就不再需要查找待删除节点的前驱节点。
~(function() {
function Node(ele) {
this.ele = ele;
this.next = null;
this.previous =null;
}
function LList() {
this.head = new Node("head");
}
LList.prototype.find = function () {};
LList.prototype.insert = function () {};
LList.prototype.display = function () {};
LList.prototype.remove = function () {};
LList.prototype.findLast = function () {};
LList.prototype.reverse = function () {};
//1.双向链表的插入
LList.prototype.find =function (item) {
var currNode = this.head;
while(currNode.ele != item) {
currNode = currNode.next;
}
return currNode;
};
LList.prototype.insert = function (newEle,item) {
var newNode = new Node(newEle);
var current = this.find(item);
newNode.next = current.next;//当前节点的后继给新节点的后继
//newNode = current.next.previous; //?当前元素的后继的前驱元素没有指定
newNode.previous = current;//当前节点给新节点的前驱
current.next = newNode;//新节点给当前节点的后继
};
LList.prototype.display = function () {
var currNode = this.head;//变量记录头节点
while(!(currNode.next == null)) {//当前节点不为空遍历链表
console.log(currNode.next.ele);
currNode = currNode.next;//指向下一个节点
}
};
var cities = new LList();
cities.insert("Beijing","head");
cities.insert("Shanghai","Beijing");
cities.insert("Guangzhou","Shanghai");
cities.insert("Chengdu","Guangzhou");
cities.display();
//2.双向链表的删除
//比单向链表的效率更高,不需要找前驱,首先先找到待删除的节点,修改前驱与后继就可以。
LList.prototype.remove = function (item) {
var currNode = this.find(item);
if(!(currNode.next == null)) {
currNode.previous.next = currNode.next;
currNode.next.previous = currNode.previous;
currNode.next = null;
currNode.previous = null;//待删除的元素的前驱和后继都设置null
}
};
console.log("----------------------");
cities.remove("Beijing");
cities.display();
console.log("----------------------");
cities.remove("Guangzhou");
cities.display();
//3.逆秩访问disReverse()
//完成反序显示链表,需要查找到最后一个节点findLast(),这样免除了从前往后遍历带来的麻烦。
LList.prototype.findLast = function () {
var currNode = this.head;
while(!(currNode.next == null)) {
currNode = currNode.next;
}
return currNode;
};
LList.prototype.reverse = function () {
var currNode = this.head;
currNode = this.findLast();
while(!(currNode.previous == null)) {
console.log(currNode.ele);
currNode = currNode.previous;//改变前驱
}
};
console.log("----------------------");
cities.reverse();
})();
三.循环链表
与单向链表是相似的,节点类型一样。区别是:让其头节点的next属性指向本身,head.next = head,这样会传导至链表的每一个节点,使得每一个节点的next属性指向链表的头节点,这样使得链表的尾节点指向了头节点,形成了一个环。性能高于双向链表;
~(function() {
function Node(ele) {
this.ele = ele;
this.next = null;
}
function LList() {
this.head = new Node("head");
this.head.next = this.head;
}
/*LList.prototype.find = function() {};
LList.prototype.insert = function() {};
LList.prototype.display = function() {};
LList.prototype.findPrevious = function() {};
LList.prototype.remove = function() {};*/
//与单向链表相似,只需修改display()方法即可;不然会成为死循环
LList.prototype.find =function (item) {
var currNode = this.head;
while(currNode.ele != item) {
currNode = currNode.next;
}
return currNode;
};
LList.prototype.insert = function (newEle,item) {
var newNode = new Node(newEle);
var current = this.find(item);
newNode.next = current.next;
current.next = newNode;
};
LList.prototype.display = function() {
var currNode = this.head;
while(!(currNode.next == null) && !(currNode.next.ele == "head")) {//这点有区别当前节点的后继不为空或者当前节点的后继元素不为头节点
console.log(currNode.next.ele);
currNode = currNode.next;
}
};
LList.prototype.findPrevious = function (item) {
var currNode = this.head;
while(!(currNode.next == null) && (currNode.next.ele != item )) {//当前节点的后继不为空或者后继节点不为所要查找的元素时
currNode = currNode.next;//修改后继链
}
return currNode;//找到时返回
};
LList.prototype.remove = function(item) {
var prevNode = this.findPrevious(item);//找到删除元素的前一个元素
if(!(prevNode.next == null)) {//待删除元素不为空
prevNode.next = prevNode.next.next;//待删除元素的前驱的后继修改为待删除元素的后继的后继
}
};
var cities = new LList();
cities.insert("Beijing","head");
cities.insert("Shanghai","Beijing");
cities.insert("Guangzhou","Shanghai");
cities.insert("Chengdu","Guangzhou");
cities.display();
console.log("--------------------");
cities.remove("Guangzhou");
cities.display();
})();
JavaScript--数据结构算法之链表的更多相关文章
- javascript数据结构之单链表
下面是用javascript实现的单链表,但是在输出的时候insert方法中存在问题,chrome的console报错说不能读取空的属性,调试了很久都没有通过,先在这里存着,以后再来修改一下. //数 ...
- 数据结构&算法-单链表
1.引言 工作一年了,感觉越来越懒散,把很多基础性的东西都慢慢遗忘了,最近想趁着还没忘完,回顾一下,整理了点笔记,分享一下. 如有错的地方,欢迎大家怒喷. 2.学习 我们就从最简单的链表开始吧. 链表 ...
- 指针与数据结构算法_链表(C语言)
一.变量: 声明一个变量系统是没有给这个变量分配内存空间的: 例: int j;//编译的时候是没有分配内存空间的 ;//计算机在编译的时候就会给这个i分配4个字节的内存空间 二.malloc动态分配 ...
- JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)
前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...
- 为什么我要放弃javaScript数据结构与算法(第五章)—— 链表
这一章你将会学会如何实现和使用链表这种动态的数据结构,这意味着我们可以从中任意添加或移除项,它会按需进行扩张. 本章内容 链表数据结构 向链表添加元素 从链表移除元素 使用 LinkedList 类 ...
- JavaScript数据结构与算法-链表练习
链表的实现 一. 单向链表 // Node类 function Node (element) { this.element = element; this.next = null; } // Link ...
- 重读《学习JavaScript数据结构与算法-第三版》- 第6章 链表(一)
定场诗 伤情最是晚凉天,憔悴厮人不堪言: 邀酒摧肠三杯醉.寻香惊梦五更寒. 钗头凤斜卿有泪,荼蘼花了我无缘: 小楼寂寞新雨月.也难如钩也难圆. 前言 本章为重读<学习JavaScript数据结构 ...
- JavaScript数据结构——链表
链表:存储有序的元素集合,但不同于数组,链表中的元素在内存中不是连续放置的.每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成. 好处:可以添加或移除任意项,它会按需扩容 ...
- 为什么我要放弃javaScript数据结构与算法(第九章)—— 图
本章中,将学习另外一种非线性数据结构--图.这是学习的最后一种数据结构,后面将学习排序和搜索算法. 第九章 图 图的相关术语 图是网络结构的抽象模型.图是一组由边连接的节点(或顶点).学习图是重要的, ...
- 为什么我要放弃javaScript数据结构与算法(第八章)—— 树
之前介绍了一些顺序数据结构,介绍的第一个非顺序数据结构是散列表.本章才会学习另一种非顺序数据结构--树,它对于存储需要快速寻找的数据非常有用. 本章内容 树的相关术语 创建树数据结构 树的遍历 添加和 ...
随机推荐
- Unified BeginFrame scheduling for Chrome
Unified BeginFrame scheduling for Chrome http://goo.gl/D1Qxrr Status: http://crbug.com/401331 and ht ...
- cookie 实现记住用户名演示 通过代码迅速理解cookie
// 登录页 可直接 tomcat部署 测试 1 package com.itheima.login; import java.io.IOException; import java.io.Print ...
- 用C3P0建立server与数据库的连接
1:在MyEclipse建立 Web Service Project 2:在project中建立servlets包 3:在包中新建Servlet文件(採用new Servlet方法可省去配置web.x ...
- OpenCv 人脸检測的学习
近期公司要组织开发分享,可是自己还是新手真的不知道分享啥了,然后看了看前段时间研究过OpenCv,那么就分享他把. openCv就不介绍了,说下人脸检測.事实上是通过openCv里边已经训练好的xml ...
- UVa 112 树求和
题意:给定一个数字,以及一个描写叙述树的字符序列,问存不存在一条从根到某叶子结点的路径使得其和等于那个数. 难点在于怎样处理字符序列.由于字符间可能有空格.换行等. 思路:本来想着用scanf的(后发 ...
- BZOJ2895: 球队预算
[传送门:BZOJ2895] 简要题意: 在一个篮球联赛里,有n支球队,球队的支出是和他们的胜负场次有关系的,具体来说,第i支球队的赛季总支出是Ci*x^2+Di*y^2,Di<=Ci.(赢得多 ...
- DNS隧道和工具
DNS Tunneling及相关实现 转自:http://www.freebuf.com/sectool/112076.html DNS Tunneling,是隐蔽信道的一种,通过将其他协议封装在DN ...
- VB.NET中文双引号的处理方法
相信朋友们也都碰到了这样的问题了,VS的IDE会不分青红皂白的把中文双引号变成英文的双引号,当然可以通过关闭自动重排功能来回避这个问题,但不是一个好的解决办法,以下这个方式不错: 如果在实际的使用中我 ...
- Sqoop Export原理和详细流程讲解
Sqoop Export原理 Sqoop Export详细流程讲解
- Eight hdu 1043 poj 1077
Description The 15-puzzle has been around for over 100 years; even if you don't know it by that name ...