数组的缺点:数组的长度固定,增删时比较困难要移动元素,而且数据填满再添加元素比较复杂。
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--数据结构算法之链表的更多相关文章

  1. javascript数据结构之单链表

    下面是用javascript实现的单链表,但是在输出的时候insert方法中存在问题,chrome的console报错说不能读取空的属性,调试了很久都没有通过,先在这里存着,以后再来修改一下. //数 ...

  2. 数据结构&算法-单链表

    1.引言 工作一年了,感觉越来越懒散,把很多基础性的东西都慢慢遗忘了,最近想趁着还没忘完,回顾一下,整理了点笔记,分享一下. 如有错的地方,欢迎大家怒喷. 2.学习 我们就从最简单的链表开始吧. 链表 ...

  3. 指针与数据结构算法_链表(C语言)

    一.变量: 声明一个变量系统是没有给这个变量分配内存空间的: 例: int j;//编译的时候是没有分配内存空间的 ;//计算机在编译的时候就会给这个i分配4个字节的内存空间 二.malloc动态分配 ...

  4. JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)

    前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...

  5. 为什么我要放弃javaScript数据结构与算法(第五章)—— 链表

    这一章你将会学会如何实现和使用链表这种动态的数据结构,这意味着我们可以从中任意添加或移除项,它会按需进行扩张. 本章内容 链表数据结构 向链表添加元素 从链表移除元素 使用 LinkedList 类 ...

  6. JavaScript数据结构与算法-链表练习

    链表的实现 一. 单向链表 // Node类 function Node (element) { this.element = element; this.next = null; } // Link ...

  7. 重读《学习JavaScript数据结构与算法-第三版》- 第6章 链表(一)

    定场诗 伤情最是晚凉天,憔悴厮人不堪言: 邀酒摧肠三杯醉.寻香惊梦五更寒. 钗头凤斜卿有泪,荼蘼花了我无缘: 小楼寂寞新雨月.也难如钩也难圆. 前言 本章为重读<学习JavaScript数据结构 ...

  8. JavaScript数据结构——链表

    链表:存储有序的元素集合,但不同于数组,链表中的元素在内存中不是连续放置的.每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成. 好处:可以添加或移除任意项,它会按需扩容 ...

  9. 为什么我要放弃javaScript数据结构与算法(第九章)—— 图

    本章中,将学习另外一种非线性数据结构--图.这是学习的最后一种数据结构,后面将学习排序和搜索算法. 第九章 图 图的相关术语 图是网络结构的抽象模型.图是一组由边连接的节点(或顶点).学习图是重要的, ...

  10. 为什么我要放弃javaScript数据结构与算法(第八章)—— 树

    之前介绍了一些顺序数据结构,介绍的第一个非顺序数据结构是散列表.本章才会学习另一种非顺序数据结构--树,它对于存储需要快速寻找的数据非常有用. 本章内容 树的相关术语 创建树数据结构 树的遍历 添加和 ...

随机推荐

  1. Oracle 流程控制语句

    分为选择语句循环语句两大类:一 选择语句1 if then ...end;set serveroutput on declare var_name1 varchar2(50):='East'; var ...

  2. php数据类型及运算

    数据类型: 标量类型: int(intege), float, string, bool 复合类型: array, object 特殊类型: null, resouce进制转换十进制转二进制decb ...

  3. poj 3613 Cow Relays(矩阵的图论意义)

    题解 用一个矩阵来表示一个图的边的存在性,即矩阵C[i,j]=1表示有一条从i到j的有向边C[i,j]=0表示没有从i到j的边.这个矩阵的k次方后C[i,j]就表示有多少条从i到j恰好经过k条边的路径 ...

  4. python ORM理解、元类

    元类 参考链接:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143191 ...

  5. POJ 3863 Business Center

    Business Center Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Origina ...

  6. 【转】 我的java web登录RSA加密

    [转] 我的java web登录RSA加密 之前一直没关注过web应用登录密码加密的问题,这两天用appscan扫描应用,最严重的问题就是这个了,提示我明文发送密码.这个的确很不安全,以前也大概想过, ...

  7. vmware启动虚拟机报错VMware Workstation has paused this virtual machine because the disk on which the virtual machine is stored is almost full. To continue, free an additional 1.4 GB of disk space.

    报错VMware Workstation has paused this virtual machine because the disk on which the virtual machine i ...

  8. hdu 1423 最长公共递增子序列 LCIS

    最长公共上升子序列(LCIS)的O(n^2)算法 预备知识:动态规划的基本思想,LCS,LIS. 问题:字符串a,字符串b,求a和b的LCIS(最长公共上升子序列). 首先我们可以看到,这个问题具有相 ...

  9. openGl超级宝典学习笔记 (2) 7个主要的几何图元

    点(GL_POINTS): 点总是正方形的像素,默认情况下,点的大小不受透视除法影响. 即无论与视点的距离怎样,它的大小都不改变.为了获得圆点.必须在抗锯齿模式下绘制点. 能够用glPointSize ...

  10. Windows App开发之文件与数据

    读取文件和目录名 这一节開始我们将陆续看到Windows App是如何操作文件的. 在Windows上读取文件名称.目录名 首先我们在XAML中定义一个Button和TextBlock,将读取文件/目 ...