数组的缺点:数组的长度固定,增删时比较困难要移动元素,而且数据填满再添加元素比较复杂。
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. python制造模块

    制造模块: 方法一: 1.mkdir /xxcd /xx 2.文件包含: 模块名.py setup.py setup.py内容如下:#!/usr/bin/env pythonfrom distutil ...

  2. Mac上vmware虚拟机Windows10安装JDK8及配置环境

    1.jdk8下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html 2.双击下载的jdk进行安装 3.安装成功之 ...

  3. 在windows下如何新建爬虫虚拟环境和进行scrapy安装

    Scrapy是Python开发的一个快速.高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据.Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改.Sc ...

  4. caffe(4) 激活层(Activation Layers)及参数

    在激活层中,对输入数据进行激活操作(实际上就是一种函数变换),是逐元素进行运算的.从bottom得到一个blob数据输入,运算后,从top输入一个blob数据.在运算过程中,没有改变数据的大小,即输入 ...

  5. BZOJ 3786: 星系探索 欧拉游览树

    一个叫 Euler-Tour-Tree 的数据结构,说白了就是用 Splay_Tree 维护欧拉序 #include <cstring> #include <algorithm> ...

  6. 搭建Lvs负载均衡群集

    一.Lvs详解 lvs内核模型 1.模型分析 用户访问的数据可以进入调度器 匹配调度器分配的虚拟IP|IP+端口(路由走向) 根据调度器的算法确定匹配的服务器 2.调度条件:基于IP.基于端口.基于内 ...

  7. js中数组增删查改unshift、push、pop、shift、slice、indexOf、concat、join

    js中数组增删查改unshift.push.pop.shift.slice.indexOf.concat.join

  8. Gonet2 游戏server框架解析之gRPC提高(5)

    上一篇blog是关于gRPC框架的基本使用,假设说gRPC仅仅是远程发几个參数,那和一个普通的http请求也没多大区别了. 所以今天我就来学习一下gRPC高级一点的用法. 流! 流能够依据用法,分为单 ...

  9. Android自定义组件系列【15】——四个方向滑动的菜单实现

    今天无意中实现了一个四个方向滑动的菜单,感觉挺好玩,滑动起来很顺手,既然已经做出来了就贴出来让大家也玩弄一下. 一.效果演示 (说明:目前没有安装Android模拟器,制作的动态图片太卡了,就贴一下静 ...

  10. Eclipse如何新建一个tomcat_server发布web项目

    方法/步骤     通过Eclipse打开一个正在开发阶段的java的web项目,没有项目的,只是为了学习的话,可以新建一个测试的java的web项目即可.在功能窗口找到如图所示的Servers窗口, ...