JavaScript----- 链表学习

news/2024/6/27 11:20:22

1、数组的缺点

  在其他语言中  数组的长度是固定的,所以数组被填满后在添加新的元素是非常困难的。在数组中添加和删除也是很麻烦的,需要把其他元素向前或者向后平移,以反映数组刚刚进行了添加或删除操作。

  在JavaScript 中数组的主要问题是,它们被实现成了对象,与其他语言(比如 C++ 和 Java) 的数组相比,效率很低

2、 定义链表

链表是由一组节点组成的集合,每个节点都使用一个对象的引用指向它的后继。指向另一 个节点的引用叫做链。

 

代码实现链表

// Node类用来表示节点
		// element 用来保存节点上的数据,next用来保存指向下一个节点的链接
		function Node(element){
			this.element = element;
			this.next = null ;
		}
		// LinkedList类 提供对链表进行操作的方法.
		// 包含插入 删除节点 在列表中查找给定的值.该类也有一个构造函数,
		// 链表只有 一个属性,那就是使用一个Node对象来保存该链表的头节点
		function LList(){
			this.head = new Node("head")
			this.find = find
			this.insert = insert;
			this.findPrevious = findPrevious;
			this.remove = remove;
			this.display = display;
		}
		//head 节点的 next 属性被初始化为 null, 当有新元素插入时, next 会指向新的元素, 所以在这里我们没有修改 next 的值。
		
		// 遍历链表,查找给定数据 并返回保存该数据的节点
	    function find(item){
			var currNode = this.head;
			while (currNode.element != item){
				currNode = currNode.next
			}
			return currNode;
		}
		// find() 方法演示了如何在链表上进行移动。 首先, 创建一个新节点, 并将链表的头节点赋
		// 给这个新创建的节点。 然后在链表上进行循环, 如果当前节点的 element 属性和我们要找
		// 的信息不符, 就从当前节点移动到下一个节点。 如果查找成功, 该方法返回包含该数据的
		// 节点; 否则, 返回 null。
		
		// 一旦找到“后面” 的节点, 就可以将新节点插入链表了。 首先, 将新节点的 next 属性设
		// 置为“后面” 节点的 next 属性对应的值。 然后设置“后面” 节点的 next 属性指向新节点。
		// insert() 方法的定义如下
		
		function insert (newElement,item) {
			var newNode = new Node(newElement);
			
			var current = this.find(item);
			newNode.next = current.next;
			current.next = newNode;
		}
		// display 用来显示链表中的元素
		function display(){
			var currNode = this.head;
			while(!(currNode.next == null)){
				console.log(currNode);
				currNode = currNode.next;
			}
		}
		// 该方法先将列表的头节点赋给一个变量,然后循环遍历链表,当前节点的next属性为null时循环结束,为
		// 了只显示包含数据的节点(换句话说,不显示头节点),程序只访问当前节点的下一个节点中保存的数据
		
		// 从链表中删除一个节点时,需要先找到待删除节点前面的节点.找到这个节点后,修改它的next属性,
		// 使其不再指向待删除节点,而是指向待删除节点的下一个节点.
		// 先定义一个 findPrevious(), 遍历链表中的元素,检查每一个节点的下一个节点中是否存储着待删除的数据.
		// 如果找到,返回该节点(即“前一个”节点),这样就可以修改它的next属性了,
		function findPrevious(item) {
			var currNode = this.head;
			while(!(currNode.next == null) && (currNode.next.element != item)){
				currNode = currNode.next
			}
			return currNode;
		}
		
		// 删除方法
		function remove(item) {
			var prevNode = this.findPrevious(item)
			if(!(prevNode.next == null)) {
				prevNode.next = prevNode.next.next;
			}
		}
		
		var cities = new LList();
		cities.insert("Conway", "head");
		cities.insert("Russellville", "Conway");
		cities.insert("Carlisle", "Russellville");
		cities.insert("Alma", "Carlisle");
		cities.display();
		console.log("------------------")
		cities.remove("Carlisle");
		cities.display();

4 双向链表
 

        
//要为 Node 类增加一个 previous 属性
        function Node(element) {
			this.element = element;
			this.next = null;
			this.previous = null; 
		}

      
		function LList() {
			this.head = new Node("head");
			this.find = find;
			this.insert = insert;
			this.display = display;
			this.remove = remove;
			this.findLast = findLast;
			this.dispReverse = dispReverse;
		}
//findLast() 方法找出了链表中的最后一个节点, 同时免除了从前往后遍历链表之苦:
		function dispReverse() {
			var currNode = this.head;
			currNode = this.findLast();
			while (!(currNode.previous == null)) {
				// print(currNode.element);
				console.log(currNode.element)
				currNode = currNode.previous;
			}
		}
// findLast() 方法找出了链表中的最后一个节点, 同时免除了从前往后遍历链表之苦:
		function findLast() {
			var currNode = this.head;
			while (!(currNode.next == null)) {
				currNode = currNode.next;
			}
			return currNode;
		}
//  双向链表的 remove() 方法比单向链表的效率更高, 因为不需要再查找前驱节点了。 首先需
//  要在链表中找出存储待删除数据的节点, 然后设置该节点前驱的 next 属性, 使其指向待删
//  除节点的后继; 设置该节点后继的 previous 属性, 使其指向待删除节点的前驱。
		function remove(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;
			}
		} 
        //findPrevious 没用了, 注释掉
		/*function findPrevious(item) {
		     var currNode = this.head;
		     while (!(currNode.next == null) && (currNode.next.element != item)) {
		             currNode = currNode.next;
		     } 
             return currNode;
		}*/
		function display() {
			var currNode = this.head;
			while (!(currNode.next == null)) {
				// print();
				console.log(currNode.next.element)
				currNode = currNode.next;
			}
		}

		function find(item) {
			var currNode = this.head;
			while (currNode.element != item) {
				currNode = currNode.next;
			}
			return currNode;
		}

        // 需要设置新节点的 previous 属性, 使其指向该节点的前驱。 
		function insert(newElement, item) {
			var newNode = new Node(newElement);
			var current = this.find(item);
			newNode.next = current.next;
			newNode.previous = current;
			current.next = newNode;
		}

		var cities = new LList();
		cities.insert("Conway", "head");
		cities.insert("Russellville", "Conway");
		cities.insert("Carlisle", "Russellville");
		cities.insert("Alma", "Carlisle");
		cities.display();
		console.log("-----------------------")
		cities.remove("Carlisle");
		cities.display();
		console.log("-----------------------")
		cities.dispReverse();

5 循环链表

 

如果你希望可以从后向前遍历链表, 但是又不想付出额外代价来创建一个双向链表, 那么就需要使用循环链表。 从循环链表的尾节点向后移动, 就等于从后向前遍历链表。


创建循环链表, 只需要修改 LList 类的构造函数:

function LList() {
     this.head = new Node("head");
     this.head.next = this.head;
     this.find = find;
     this.insert = insert;
     this.display = display;
     this.findPrevious = findPrevious;
     this.remove = remove;
}
循环链表的 display() 方法如下所示:
function display() {
    var currNode = this.head;
    while (!(currNode.next == null) && !(currNode.next.element == "head")) {
           console.log(currNode.next.element)
           currNode = currNode.next;
    }
}

知道了怎么修改 display() 方法, 你应该会修改其他方法了吧? 这样就可以将一个标准的链表转换成一个循环链表了。
 

 

 

 

 

 

 

 

 

 

 

 

 


http://www.niftyadmin.cn/n/3655838.html

相关文章

JavaScript ---- 字典学习

字典是一种以键-值对形式存储数据的数据结构 JavaScript的object类就是以字典的形式设计的, function Dictionary() {this.add add;this.datastore new Array();this.find find;this.remove removethis.showAll showAllthis.count countthis.clear clear}f…

VS2005 IDE的bug?

在修改医疗程序的时候,遇到这样的一个问题,原来的程序是VS2003开发的VB.net程序,目前我转移到VS2005来,发现有些窗体界面无法打开,报出如下错误:(注,以前记得打开成功过几次&#xf…

JavaScript------散列学习

散列是一种常用的数据存储技术,散列后的数据可以快速的插入或取用。 散列使用的数据结构叫做 散列表。 在散列表上插入、删除和取用数据都非常的快,但是对于查找操作来说却效率低下,比如查找一组数据中的最大值和最小值。这些操作得求助于其…

.Net Mirco Framework 2007技术大会

.Net Mirco Framework 2007技术大会2006年在《程序员》杂志上通过看马宁的专栏文章,第一次知道了.Net MF。一年后的今天终于近距离地接触了.Net Mirco Frmaework,对MF有了一定的感性认识。最近公司很多项目都有大量嵌入式设备使用,由于WinCE系…

JavaScript ---- 集合学习

集合(set)是一种包含不同元素的数据结构。集合中的元素称为成员。集合的两个最重 要特性是: 1、集合中的成员是无序的 2、集合中不允许相同成员存在 1 集合的定义、操作和属性 1.1 集合的定义 不包含任何成员的集合称为空集,全集则是包含一切可能成员的…

火车站信息服务系统之LED大屏显示

最近比较忙,有一段时间没有更新blog了。一是忙隧道广告通信系统升级工作(两个方案同时做,linux和wince方案),二是忙北京南站的信息服务系统,由于该项目我们介入的比较晚,主要是参与型厂商&#…

2020-12-06 instanceof 的原理,并代码实现

解答 : 遍历A的原型链,如果能找到B的prototype,返回true 找不到返回false const instanceOf (A, B) > {let p A;while (p) {if (p B.prototype) {return true}p p.__proto__;}return false }

嵌入式Linux编程--我的第一次艰难跋涉

其实从很早我就想深入学习Linux,但时间有限,并且Linux门槛挺高,不是很容易上手。最近由于隧道项目中用到嵌入式Linux(Arm CPU上的Linux),并且提供硬件的单位针对Linux的编程收费很高,并且时间很…