zoukankan      html  css  js  c++  java
  • JavaScript数据结构 --- 链表

    JavaScript数据结构 --- 链表

    数组不总是组织数据的最佳数据结构,因为在很多编程语言中,数组的长度是固定的,所以当数组被数据填满时,在要加入数据会很困难。在数组中添加和删除元素也很麻烦,需要移动其它元素。
    JavaScript中的数组是对象,与其它语言(Java,C++)相比,效率很低。我们可以考虑用链表来替代它。

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

    链表元素靠相互之间的关系进行引用,许多链表的实现都在链表最前面有一个特殊的节点,叫头结点,链表的尾元素可以指向一个 null 节点。
    link

    链表中插入节点效率很高。插入节点时,需要修改它前面的节点(前驱),使其指向新加入的节点,而新加入的节点则指向原来前驱指向的节点。
    link2

    从链表中删除一个元素也很简单。将待删除元素的前驱节点指向待删除元素的后继节点。
    link3

    1. 设计一个基于对象的链表


    1.1 Node类

    Node 类包含两个属性:element 用来保存节点上的数据,next 用来保存指向下一个节点的链接。

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

    1.2 LinkedList类

    LList 类提供了对链表进行操作的方法。

    function LList() {
    	this.head = new Node("head"); // 头节点
    	this.find = find;
    	this.insert = insert;
    	this.remove = remove;
    	this.display = display;
    }
    

    1.3 插入新节点
    find() 方法遍历链表,查找给定数据,如果找到数据,该方法就返回保存该数据的节点。

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

    在一个已知节点后面插入节点时,用 find() 找到这个节点后,就可以将新节点插入链表了。首先,将新节点的 next 属性设置为这个节点的 next 属性对应的值,然后设置这个节点的 next 属性指向新节点。

    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)) {
    		cosole.log(currNode.next.element);
    		currNode = currNode.next;
    	}
    }
    

    1.4 从链表中删除一个节点

    从链表中删除节点时,需要先找到待删除节点前面的节点。找到这个节点后,修改它的 next 属性,使其不再指向待删除节点,而是指向待删除节点的下一个节点。
    可以先定义一个方法 findPrevious() 来遍历链表中的元素,检查每一个节点的下一个节点中是否存储着待删除数据。如果找到,返回该节点(待删除节点的”前一个“节点),这样就可以修改它的 next 属性了。

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

    再来写 remove() 方法。

    function remove(item) {
    	var prevNode = this.findPrevious(item);
    	if (!(prevNode.next == null)) {
    		prevNode.next = prevNode.next.next;
    	}
    }
    

    这个地址包含了完整的代码

    LinkedList


    双向链表
    从链表的头节点遍历到尾节点很容易,但从后往前遍历比较难。可以通过给 Node 对象增加一个属性,该属性存储指向前驱节点的链接。
    2link

    先为 Node 类增加一个 previous 属性。

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

    双向链表的 insert() 方法需要设置新节点的 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;
    }
    

    双向链表的 remove() 方法比单向链表的效率更高,不需要查找前驱节点。首先需要在链表中找出存储待删除数据的节点,然后设置该节点前驱的 next 属性,使其指向待删除节点的后继;设置该节点后继的 previous 属性,使其指向待删除节点的前驱。
    2link2
    remove() 方法的定义。

    function remove(item) {
    	var currNode = this.find(item);
    	if (!(currNode == null)) {
    		currNode.previous.next = currNode.next;
    		currNode.next.previous = currNode.previous;
    		currNode.next = null;
    		currNode.previous = null;
    	}
    }
    

    给双向链表增加一个 findLast() 工具方法,用来查找最后的节点.

    function findLast() {
    	var currNode = this.head;
    	while (!(currNode.next == null)) {
    		currNode = currNode.next;
    	}
    	return currNode;
    }
    

    在 findLast() 的基础上写一个反向显示双向链表中的元素的方法 dispReverse() 。

    function dispReverse() {
    	var currNode = this.head;
    	currNode = this.findLast();
    	while (!(currNode.previous == null)) {
    		console.log(currNode.element);
    		currNode = currNode.previous;
    	}
    }
    

    双向链表 LList 完整代码。

    LList


    参考资料:
    JavaScript高级程序设计
    JavaScript MDN
    Data Structures and Algorithms with JavaScript

  • 相关阅读:
    Java实现 LeetCode 50 Pow(x,n)
    Java实现 LeetCode 50 Pow(x,n)
    Java实现 LeetCode 49 字母异位词分组
    Java实现 LeetCode 49 字母异位词分组
    Java实现 LeetCode 49 字母异位词分组
    Java实现 LeetCode 48 旋转图像
    Java实现 LeetCode 48 旋转图像
    Java实现 LeetCode 48 旋转图像
    Java实现 LeetCode 47 全排列 II(二)
    Java实现 LeetCode 47 全排列 II(二)
  • 原文地址:https://www.cnblogs.com/zhoufulin/p/5006044.html
Copyright © 2011-2022 走看看