JS数据结构与算法知识点--->链表(单向、双向)

此数据结构算法知识点系列笔记均是看coderwhy老师视频整理得出!!!

链表和数组一样,用于**存储一系列的元素**,但是链表和数组的**实现机制完全不同**

数组存在的缺点

要存储多个元素,数组(或称为列表)可能是最常用的数据结构。
我们之前说过,几乎每一种编程语言都有默认实现数组结构.。
但数组也有很多缺点:

  1. 数组的创建通常需要申请一段**连续的内存空间(一整块的内存)**并且大小是固定的(大多数编程语言数组都是固定的),所以当当前数组不能满足容量需求时,需要扩容.(一般情况下是申请一个更大的数组,比如2倍.然后将原数组中的元素复制过去)
  2. 而且在数组开头或中间位置插入数据的成本很高,需要进行大量元素的位移.
  3. 尽管我们已经学过的JavaScript的Array类方法可以帮我们做这些事,但背后的原理依然是这样。

 链表的特点及优势、劣势

特点

  1. 链表中的元素在内存中**不必是连续的空间**
  2. 链表的每个元素由一个存储**元素本身的节点**和一个**指向下一个元素的引用**组成

优势

  1. 内存空间不必须是连续的,灵活的内存动态管理
  2. 在创建时不必确定大小,可以**无限的延伸**
  3. 在**插入和删除**数据时,**时间复杂度**可以达到O(1),相对数组效率高很多。但是如果是通过下标值进行相关操作,数组的效率时非常高的。

劣势

  1. 链表访问任何一个位置的元素时,都需要**从头开始访问**.(无法跳过第一个元素访问任何一个元素).
  2. 无法通过下标直接访问元素,需要从头一个个访问,直到找到对应的元素.

链表到底是什么?

链表的常见操作 

  • >+ append(element):向列表尾部添加一个新的项
  • >+ insert(position, element):向列表的特定位置插入一个新的项。
  • >+ get(position):获取对应位置的元素
  • >+ indexOf(element):返回元素在列表中的索引。如果列表中没有该元素则返回-1。
  • >+ update(position):修改某个位置的元素
  • >+ removeAt(position):从列表的特定位置移除一项。
  • >+ remove(element):从列表中移除一项。
  • >+ isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false。
  • >+ size():返回链表包含的元素个数。与数组的length属性类似。
  • >+ toString():由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。

单向链表的封装

      // 单向链表
      // 封装链表类
      function LinkedList() {
        // 内部类:节点类
        function Node(data) {
          this.data = data;
          this.next = null;
        }
        // 属性
        this.head = null;
        this.length = 0;
        // 1. append 在尾部添加一项
        LinkedList.prototype.append = function (data) {
          // 创建新节点
          var newNode = new Node(data);
          // 判断是否添加的是第一个节点
          if (this.length === 0) {
            this.head = newNode;
          } else {
            var current = this.head;
            // 找到最后一个节点
            while (current.next) {
              current = current.next;
            }
            // 最后节点指向新节点
            current.next = newNode;
          }
          this.length += 1;
        };

        //2. toString
        LinkedList.prototype.toString = function () {
          var current = this.head;
          var listString = "";
          while (current) {
            listString += current.data + " ";
            current = current.next;
          }
          return listString;
        };

        //3. insert
        LinkedList.prototype.insert = function (position, data) {
          //对position进行越界判断
          if (position < 0 || position > this.length) return false;
          var newNode = new Node(data);
          //   判断插入的位置是否为第一个
          if (position === 0) {
            newNode.data = data;
            newNode.next = this.head;
            this.head = newNode;
          } else {
            var index = 0;
            var current = this.head;
            var prev = null;
            while (index++ < position) {
              prev = current;
              current = current.next;
            }
            newNode.next = current.next;
            prev = newNode;
          }
        };

        // 4.get
        LinkedList.prototype.get = function (position) {
          if (position < 0 || position >= this.length) return false;
          var current = this.head;
          var index = 0;
          while (index < position) {
            current = current.next;
            index++;
          }
          return current.data;
        };
        //5.updata
        LinkedList.prototype.update = function (position, newData) {
          if (position < 0 || position >= this.length) return false;
          var current = this.head;
          var index = 0;
          while (index++ < position) {
            current = current.next;
          }
          current.data = newData;
          return true;
        };
        //6.indexOf
        LinkedList.prototype.indexOf = function (data) {
          var current = this.head;
          var index = 0;
          while (current) {
            if (current.data == data) {
              return index;
            }
            current = current.next;
            index += 1;
          }
          return -1;
        };
        //7.removeAt
        LinkedList.prototype.removeAt = function (position) {
          //  越界判断
          if (position < 0 || position >= this.length) return null;
          var current = this.head;
          if (position == 0) {
            this.head = current.next;
          } else {
            var index = 0;
            var prev = null;
            while (index++ < position) {
              prev = current;
              current = current.next;
            }
            prev.next = current.next;
          }
          this.length -= 1;
          return current.data;
        };
        //8.remove
        LinkedList.prototype.remove = function (data) {
          var position = this.indexOf(data);
          return this.removeAt(position);
        };
        //9.isEmpty
        LinkedList.prototype.isEmpty = function () {
          return this.length == 0;
        };
        //10.size
        LinkedList.prototype.size = function () {
          return this.length;
        };
      }

双向链表

双向链表的特点

  • 可以使用一个head和一个tail分别指向头部和尾部的节点
  • 每个节点都由三部分组成:前一个节点的指针(prev)/保存的元素(item)/后一个节点的指针(next)
  • 双向链表的第一个节点的prev是null
  • 双向链表的最后的节点的next是null

双向链表的常用方法

  • append(element):向列表尾部添加一个新的项
  • insert(position, element):向列表的特定位置插入一个新的项。
  • get(position):获取对应位置的元素
  • indexOf(element):返回元素在列表中的索引。如果列表中没有该元素则返回-1。
  • update(position):修改某个位置的元素
  • removeAt(position):从列表的特定位置移除一项。
  • remove(element):从列表中移除一项。
  • isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false。
  • size():返回链表包含的元素个数。与数组的length属性类似。
  • toString():由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。
  • forwardString(): 返回正向遍历节点字符串形式
  • backwordString():返回反向遍历的节点字符串形式

双向链表的封装

      // 双向链表类的封装、
      function DoublyLinkedList() {
        // 内部节点类
        function Node(data) {
          this.data = data;
          this.prev = null;
          this.next = null;
        }
        // 属性
        this.head = null;
        this.tail = null;
        this.length = 0;
        // 1.append
        DoublyLinkedList.prototype.append = function (data) {
          var newNode = new Node(data);
          // 判断链表中是否有节点
          if (this.length == 0) {
            this.head = newNode;
            this.tail = newNode;
          } else {
            newNode.prev = this.tail;
            this.tail.next = newNode;
            this.tail = newNode;
          }
          this.length += 1;
        };

        // 2.toString
        DoublyLinkedList.prototype.toString = function () {
          return this.backwardString();
        };
        // 3.forwardString 向前遍历组成字符串
        DoublyLinkedList.prototype.forwardString = function () {
          var current = this.tail;
          var resultString = "";
          while (current) {
            resultString += current.data + " ";
            current = current.prev;
          }
          return resultString;
        };
        // 4.backwardString 向后遍历组成字符串
        DoublyLinkedList.prototype.backwardString = function () {
          var current = this.head;
          var resultString = "";
          while (current) {
            resultString += current.data + " ";
            current = current.next;
          }
          return resultString;
        };
        // 5.insert
        DoublyLinkedList.prototype.insert = function (position, data) {
          if (position < 0 || position > this.length) return false;
          var newNode = new Node(data);
          // 链表中为空
          if (this.length == 0) {
            this.head = newNode;
            this.tail = newNode;
          } else {
            if (position == 0) {
              this.head.prev = newNode;
              newNode.next = this.head;
              this.head = newNode;
            } else if (position == this.length) {
              newNode.prev = this.tail;
              this.tail.next = newNode;
              this.tail = newNode;
            } else {
              var current = this.head;
              var index = 0;
              while (index++ < position) {
                current = current.next;
              }
              newNode.prev = current.prev;
              newNode.next = current;
              current.prev.next = newNode;
              current.prev = newNode;
            }
          }
          this.length += 1;
          return true;
        };

        // 6.get
        DoublyLinkedList.prototype.get = function (position) {
          if (position < 0 || position >= this.length) return null;
          if (this.length / 2 > position) {
            var index = 0;
            var current = this.head;
            while (index++ < position) {
              current = current.next;
            }
            return current.data;
          } else {
            var index = this.length - 1;
            var current = this.tail;
            while (index-- > position) {
              current = current.prev;
            }
            return current.data;
          }
        };

        //7.indexOf
        DoublyLinkedList.prototype.indexOf = function (data) {
          var current = this.head;
          var index = 0;
          while (current) {
            if (current.data == data) {
              return index;
            }
            current = current.next;
            index++;
          }
          return -1;
        };
        // 8.update
        DoublyLinkedList.prototype.update = function (position, data) {
          if (position < 0 || position >= this.length) return false;
          var current = this.head;
          var index = 0;
          while (index++ < position) {
            current = current.next;
          }
          current.data = data;
          return true;
        };

        // 9.removeAt()
        DoublyLinkedList.prototype.removeAt = function (position) {
          if (position < 0 || position >= this.length) return null;
          var current = this.head;

          if (this.length == 1) {
            this.head = 0;
            this.tail = 0;
          } else {
            if (position == 0) {
              this.head.next.prev = null;
              this.head = this.head.next;
            } else if (position == this.length - 1) {
              current = this.tail;
              this.tail.prev.next = null;
              this.tail = this.tail.prev;
            } else {
              var index = 0;
              while (index++ < position) {
                current = current.next;
              }
              current.prev.next = current.next;
              current.next.prev = current.prev;
            }
          }
          this.length -= 1;
          return current.data;
        };

        // 10.remove
        DoublyLinkedList.prototype.remove = function (data) {
          var index = this.indexOf(data);
          return this.removeAt(index);
        };
        // 11.isEmpty
        DoublyLinkedList.prototype.isEmpty = function () {
          return this.length == 0;
        };
        // 12.size
        DoublyLinkedList.prototype.size = function () {
          return this.length;
        };
        // 13.getHead
        DoublyLinkedList.prototype.getHead = function () {
          return this.head.data;
        };
        // 14.getTail
        DoublyLinkedList.prototype.getTail = function () {
          return this.tail.data;
        };
      }

      var list = new DoublyLinkedList();
      list.append("1111");
      list.append("222");
      alert(list);
      // console.log(list);
      alert(list.backwardString());
      alert(list.forwardString());
      list.insert(0, "第一位插入");
      list.insert(3, "末尾插入");
      list.insert(1, "中间插入");
      alert(list);
      alert(list.get(0));
      alert(list.indexOf("1111"));
      alert(list.indexOf("aaaa"));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BoZai_ya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值