• JavaScript数据结构与算法(七) 双向链表的实现


    TypeScript方式实现源码

    // 双向链表和普通链表的区别在于, 在链表中,
    // 一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的:一个链向下一个元素,
    // 另一个链向前一个元素,如下图所示:
    // 
    // Node类里有prev属性(一个新指针) ,在DoublyLinkedList类里也有用来保存对列表最后一
    // 项的引用的tail属性。 
    
    // 双向链表提供了两种迭代列表的方法:从头到尾,或者反过来。我们也可以访问一个特定节
    // 点的下一个或前一个元素。在单向链表中,如果迭代列表时错过了要找的元素,就需要回到列表
    // 起点,重新开始迭代。这是双向链表的一个优点。
    // 代码角度
    //   每个节点设置两个指针,关联相邻的前后节点.提供逆向遍历,链表篇提到,链表是针对大量删除与添加场景下使用的.因此双向链表是针对普通链表的功能为基础,强化了遍历的功能
    // 抽象
    //   想了很久找不到现实中的场景,还是拿火车来理解吧.早期火车就像普通链表,具有重组车厢的功能.而随着科技的进步,双向列车出来了,优势便是不用再每次脱离车头,开到转盘进行掉头
    //   然后再行驶.双向链表便是双向列车,它弱化了车头的概念,前后皆可是车头.
    // 总结
    //   单向链表优势在于可执行大量删除、增加操作并不用像数组那样需要重新排序.劣势则是每次便利必须从头开始,无端增加许多系统开销.假如有这种场景,知道某个节点,我需要找到
    //   该节点的爷爷,再找他爷爷的儿子,再找他儿子的孙子.我们大脑瞬间可以计算出,这不就是要找当前节点的儿子吗?的确!我们就是要程序能够这样做,但是单向链表就是一根筋,不具备
    //   这样的智商,这时双向链表优势则非常明显
      1 class Node {
      2     element;
      3     next;
      4     prev; // 新增的
      5     constructor(element) {
      6         this.element = element;
      7         this.next = null;
      8         this.prev = null;
      9     }
     10 }
     11 
     12 /**
     13  * 双向链表
     14  * @name DoublyLinkedList
     15  */
     16 class DoublyLinkedList {
     17     private length = 0;
     18     head = null;
     19     tail = null; // 新增的
     20 
     21     /**
     22      * 向列表尾部添加一个新的项
     23      * @param element 
     24      */
     25     public append(element) {
     26         let node = new Node(element), current;
     27 
     28         if (this.head === null) {
     29             this.head = node;
     30         } else {
     31             current = this.head;
     32 
     33             // 循环列表,知道找到最后一项
     34             while (current.next) {
     35                 current = current.next;
     36             }
     37 
     38             // 找到最后一项,将其next赋为node,建立链接
     39             current.next = node;
     40         }
     41         this.length++; // 更新列表长度    
     42     }
     43     /**
     44      * 向列表的特定位置插入一个新的项
     45      * @param position 
     46      * @param element 
     47      */
     48     public insert(position, element) {
     49         // 检查越界值
     50         if (position >= 0 && position <= this.length) {
     51             let node = new Node(element),
     52                 current = this.head,
     53                 previous,
     54                 index = 0;
     55 
     56             if (position === 0) { // 在第一个位置添加
     57                 if (!this.head) { // 新增的
     58                     this.head = node;
     59                     this.tail = node;
     60                 } else {
     61                     node.next = current;
     62                     current.prev = node; // 新增的
     63                     this.head = node;
     64                 }
     65             } else if (position === this.length) { // 最后一项 新增的
     66                 current = this.tail;
     67                 current.next = node;
     68                 node.prev = current;
     69                 this.tail = node;
     70             } else {
     71                 while (index++ < position) {
     72                     previous = current;
     73                     current = current.next;
     74                 }
     75                 node.next = current;
     76                 previous.next = node;
     77 
     78                 current.prev = node; // 新增的
     79                 node.prev = previous; // 新增的
     80             }
     81             this.length++; // 更新列表长度
     82             return true;
     83         } else {
     84             return false;
     85         }
     86     }
     87     /**
     88      * 从列表的特定位置移除一项
     89      * @param position 
     90      */
     91     public removeAt(position) {
     92         // 检查越界值
     93         if (position > -1 && position < this.length) {
     94             let current = this.head,
     95                 previous,
     96                 index = 0;
     97 
     98             // 移除第一项
     99             if (position === 0) {
    100                 this.head = current.next;
    101 
    102                 // 如果只有一项,更新tail // 新增的
    103                 if (this.length === 1) {
    104                     this.tail = null;
    105                 } else {
    106                     this.head.prev = null;
    107                 }
    108             }
    109             else if (position === this.length - 1) { // 新增的
    110                 current = this.tail;
    111                 this.tail = current.prev;
    112                 this.tail.next = null;
    113             }
    114             else {
    115                 while (index++ < position) {
    116                     previous = current;
    117                     current = current.next;
    118                 }
    119                 // 将previous与current的下一项链接起来:跳过current,从而移除它
    120                 previous.next = current.next;
    121                 current.next.prev = previous; // 新增的
    122             }
    123             this.length--;
    124             return current.element;
    125         } else {
    126             return null;
    127         }
    128     }
    129     /**
    130      * 从列表中移除一项
    131      * @param element 
    132      */
    133     public remove(element) {
    134         let index = this.indexOf(element);
    135         return this.removeAt(index);
    136     }
    137     /**
    138      * :返回元素在列表中的索引。如果列表中没有该元素则返回-1
    139      * @param element 
    140      */
    141     public indexOf(element) {
    142         let current = this.head,
    143             index = -1;
    144 
    145         while (current) {
    146             if (element === current.element) {
    147                 return index;
    148             }
    149             index++;
    150             current = current.next;
    151         }
    152         return -1;
    153     }
    154     /**
    155      * 如果链表中不包含任何元素, 返回true, 如果链表长度大于0则返回false
    156      */
    157     public isEmpty() {
    158         return this.length === 0;
    159     }
    160     /**
    161      * 返回链表包含的元素个数。与数组的length属性类似
    162      */
    163     public size() {
    164         return this.length;
    165     }
    166     /**
    167      * 由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值
    168      */
    169     public toString() {
    170         let current = this.head,
    171             string = '';
    172 
    173         while (current) {
    174             string += current.element;
    175             current = current.next;
    176         }
    177         return string;
    178     }
    179     public getHead() {
    180         return this.head;
    181     }
    182     public print() {
    183         console.log(this.toString());
    184     }
    185 }
    View Code
     
    JavaScript 方式实现源码
      1 var Node = (function () {
      2     function Node(element) {
      3         this.element = element;
      4         this.next = null;
      5         this.prev = null;
      6     }
      7     return Node;
      8 }());
      9 /**
     10  * 双向链表
     11  * @name DoublyLinkedList
     12  */
     13 var DoublyLinkedList = (function () {
     14     function DoublyLinkedList() {
     15         this.length = 0;
     16         this.head = null;
     17         this.tail = null; // 新增的
     18     }
     19     /**
     20      * 向列表尾部添加一个新的项
     21      * @param element
     22      */
     23     DoublyLinkedList.prototype.append = function (element) {
     24         var node = new Node(element), current;
     25         if (this.head === null) {
     26             this.head = node;
     27         }
     28         else {
     29             current = this.head;
     30             // 循环列表,知道找到最后一项
     31             while (current.next) {
     32                 current = current.next;
     33             }
     34             // 找到最后一项,将其next赋为node,建立链接
     35             current.next = node;
     36         }
     37         this.length++; // 更新列表长度    
     38     };
     39     /**
     40      * 向列表的特定位置插入一个新的项
     41      * @param position
     42      * @param element
     43      */
     44     DoublyLinkedList.prototype.insert = function (position, element) {
     45         // 检查越界值
     46         if (position >= 0 && position <= this.length) {
     47             var node = new Node(element), current = this.head, previous = void 0, index = 0;
     48             if (position === 0) {
     49                 if (!this.head) {
     50                     this.head = node;
     51                     this.tail = node;
     52                 }
     53                 else {
     54                     node.next = current;
     55                     current.prev = node; // 新增的
     56                     this.head = node;
     57                 }
     58             }
     59             else if (position === this.length) {
     60                 current = this.tail;
     61                 current.next = node;
     62                 node.prev = current;
     63                 this.tail = node;
     64             }
     65             else {
     66                 while (index++ < position) {
     67                     previous = current;
     68                     current = current.next;
     69                 }
     70                 node.next = current;
     71                 previous.next = node;
     72                 current.prev = node; // 新增的
     73                 node.prev = previous; // 新增的
     74             }
     75             this.length++; // 更新列表长度
     76             return true;
     77         }
     78         else {
     79             return false;
     80         }
     81     };
     82     /**
     83      * 从列表的特定位置移除一项
     84      * @param position
     85      */
     86     DoublyLinkedList.prototype.removeAt = function (position) {
     87         // 检查越界值
     88         if (position > -1 && position < this.length) {
     89             var current = this.head, previous = void 0, index = 0;
     90             // 移除第一项
     91             if (position === 0) {
     92                 this.head = current.next;
     93                 // 如果只有一项,更新tail // 新增的
     94                 if (this.length === 1) {
     95                     this.tail = null;
     96                 }
     97                 else {
     98                     this.head.prev = null;
     99                 }
    100             }
    101             else if (position === this.length - 1) {
    102                 current = this.tail;
    103                 this.tail = current.prev;
    104                 this.tail.next = null;
    105             }
    106             else {
    107                 while (index++ < position) {
    108                     previous = current;
    109                     current = current.next;
    110                 }
    111                 // 将previous与current的下一项链接起来:跳过current,从而移除它
    112                 previous.next = current.next;
    113                 current.next.prev = previous; // 新增的
    114             }
    115             this.length--;
    116             return current.element;
    117         }
    118         else {
    119             return null;
    120         }
    121     };
    122     /**
    123      * 从列表中移除一项
    124      * @param element
    125      */
    126     DoublyLinkedList.prototype.remove = function (element) {
    127         var index = this.indexOf(element);
    128         return this.removeAt(index);
    129     };
    130     /**
    131      * :返回元素在列表中的索引。如果列表中没有该元素则返回-1
    132      * @param element
    133      */
    134     DoublyLinkedList.prototype.indexOf = function (element) {
    135         var current = this.head, index = -1;
    136         while (current) {
    137             if (element === current.element) {
    138                 return index;
    139             }
    140             index++;
    141             current = current.next;
    142         }
    143         return -1;
    144     };
    145     /**
    146      * 如果链表中不包含任何元素, 返回true, 如果链表长度大于0则返回false
    147      */
    148     DoublyLinkedList.prototype.isEmpty = function () {
    149         return this.length === 0;
    150     };
    151     /**
    152      * 返回链表包含的元素个数。与数组的length属性类似
    153      */
    154     DoublyLinkedList.prototype.size = function () {
    155         return this.length;
    156     };
    157     /**
    158      * 由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值
    159      */
    160     DoublyLinkedList.prototype.toString = function () {
    161         var current = this.head, string = '';
    162         while (current) {
    163             string += current.element;
    164             current = current.next;
    165         }
    166         return string;
    167     };
    168     DoublyLinkedList.prototype.getHead = function () {
    169         return this.head;
    170     };
    171     DoublyLinkedList.prototype.print = function () {
    172         console.log(this.toString());
    173     };
    174     return DoublyLinkedList;
    175 }());
    View Code
  • 相关阅读:
    个人总结
    再见,我的伪算法竞赛生涯。
    C语言实现迷宫小游戏
    关于第九届蓝桥杯决赛
    蓝桥杯近3年决赛题之3(17年b组)
    蓝桥杯近3年决赛题之二(16年b组)
    蓝桥杯近三年决赛题之一(15年B组)
    第九届蓝桥杯C/C++B组省赛感想
    读书笔记《程序员的自我修养—链接、装载与库》
    蓝桥杯近3年初赛题之三(17年b组)
  • 原文地址:https://www.cnblogs.com/menu/p/6971946.html
Copyright © 2020-2023  润新知