[数据结构与算法-小白系列]第2️⃣天链表

时间:2021-1-8 作者:admin

回顾

第一天我们学习了栈和队列[数据结构与算法-小白系列]第1️⃣天栈、队列
今天我们来学习下另外一种重要的数据结构链表,个人感觉链表理解起来比栈和队列要难,但不管咱们样 干就完了

链表栈,队列有着本质不同

在上一篇中,我们是通过javascript数组实现的栈和队列,我们知道,数组是线性结构,也就是说数组中的数据是一个一个连续的存放的,我们可以通过下标来读取元素,所以栈和队列都是线性储存数据的,而链表就不是了,我们可以先记着链表是链式存储的线性表

链表是为了解决什么问题?

存在是有原因的,我们要记着 每一种数据结构都对应着一种典型的应用场景

那链表是为了解决什么问题呢?

我们先来盘盘栈和队列这种数据结构有什么缺点,也可以说数组有什么缺点

首先数组是线性存储数据,可以通过下标来读取数据,固然它的 读取速度非常高,但是如果我们向数据里面新增或删除数据,数据的执行效率就不那么高了,下面我们来看看向数组里面新增数据的过程

有个数组[2,4,6,8],现在我们需要在2,4之间新增一个3

可以看出我们在插入一个数据的同时,需要改变三个数据的位置,那如果数据量非常大呢,可见 数组在新增和修改数据的时候效率比较低

而链表就是为了解决这个问题而生

链表的结构

链表的精髓在于指针,我们可以把链表中的元素称之为节点,每个节点之间都是通过指针建立关系

那问题来了,为什么要通过指针建立关系呢?

这就要研究下链表是如何存储数据的了,我们知道数组存储是连续的,所以可以通过数组的索引拿到值,而链表的存储数据是离散的,那我们如何知道一个节点下个数据是什么呢?那就只能通过指针,买个节点都保存下个节点的引用,如下所示:

现在如果我们要添加内容只需要移动指针就可以了,如下我们要在2和3中添加一个4

现在的数据结构为1->2->4->3如果要删除元素4的话直接让2的指针直接指向3即可 1->2->3

原理很简单,下面就让我们用代码实现一边把

使用JavaScript实现链表

单向链表

单向列表就是每个节点都保存的有指向下一个节点的引用,这个指向只能是单向的,比如 1->2->3->4,那我们用代码怎么实现呢?
首先我们要创建一个节点

function Node(data){
    this.data = data
    this.next = null
}

我们封装一个链表类,其中有以下几个方法:

  • append 追加
  • insert 插入
  • get 获取对应下标的数据
  • indexof 获取对应数据下标值
  • updata 跟新节点
  • remove 删除节点
  • toString 链表字符串化
function linkedList() {
  //链表的节点类
  function Node(data) {
    this.data = data;
    this.next = null;
  }
  this.head = null; // 链表的hede 可以理解为指针
  this.length = 0; //链表的长度
  // 添加方法
  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++;
  };
  // 插入方法,可以把数据插入到链表的任何地方
  linkedList.prototype.insert = function(position, data) {
    // 对 position 越界判断
    if (position < 0 || position > this.length) {
      return false;
    }
    var newNode = new Node(data);
    // 判断是不是插入到第一个
    if (position == 0) {
      newNode.next = this.head;
      this.head = newNode;
    } else {
      var index = 0;
      var current = this.head;
      var previous = null; // 记录上一个节点
      while (index++ < position) {
        previous = current;
        current = current.next;
      }

      newNode.next = current;
      previous.next = newNode;
    }
    this.length++;
    return true;
  };
  // 获取对应位置上的数据
  linkedList.prototype.get = function(position) {
    if (position < 0 || position >= this.length) {
      return null;
    }
    var current = this.head;
    var index = 0;
    while (index++ < position) {
      current = current.next;
    }
    return current.next;
  };
  // 获取对应数据的下标值
  linkedList.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;
  };
  // 更新方法
  linkedList.prototype.updata = 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;
  };
  // 根据位置 删除元素
  linkedList.prototype.removeAt = function(position) {
    if (position < 0 || position >= this.length) {
      return false;
    }
    //  删除第一个
    if (position == 0) {
      this.head = this.head.next;
    } else {
      var current = this.head;
      var previous = null;
      var index = 0;
      while (index++ < position) {
        position = current;
        current = current.next;
      }
      previous.next = current.next;
    }
    this.length -= 1;
    return true;
  };
  // 字符串化
  linkedList.prototype.toString = function() {
    var current = this.head;
    var listString = "";
    // 循环获取一个个节点
    while (current) {
      listString += current.data + " ";
      current = current.next;
    }
    return listString;
  };
}

双向链表

每个节点都记录了他上一个和下一个节点的引用,如:

// 双向链表
function DoublyList() {
  this.head = null; //指针 指向第一个
  this.tail = null; // 指针 指向最后一个
  this.length = 0; // 列表的长度
  // 内部节点类
  function Node(data) {
    this.data = data;
    this.prev = null;
    this.next = null;
  }
  // 插入到链表的尾部
  DoublyList.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;
  };
  // 插入
  DoublyList.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;
    }
    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.next = current;
      newNode.prev = current.prev;
      current.prev.next = newNode;
      current.prev = newNode;
    }
    this.length += 1;
  };
  // 获取对应下标的数据
  DoublyList.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;
    }
    return current.data;
  };
  // 获取对应值的下标
  DoublyList.prototype.indexOf = function(data) {
    var current = this.head;
    var index = 0;
    while (current) {
      if (current.data == data) {
        return index;
      }
      index++;
      current = current.next;
    }
    return -1;
  };
  // 根据下标更新
  DoublyList.prototype.updata = 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;
  };
  // 根据下标删除
  DoublyList.prototype.removeAt = function(position) {
    if (position < 0 || position > this.length) return false;
    if (this.length == 1) {
      this.head = null;
      this.tail = null;
    }

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

      current.prev.next = current.next;
      current.next.prev = current.prev;
    }
  };
  DoublyList.prototype.toString = function() {
    return this.bacckwardToString();
  };
  // 从后向前遍历
  DoublyList.prototype.forwardToString = function() {
    var current = this.tail;
    var resString = "";
    while (current) {
      current = current.prev;
      resString += current.data + " ";
    }
    return resString;
  };
  // 从前向后遍历
  DoublyList.prototype.bacckwardToString = function() {
    var current = this.head;
    var resString = "";
    while (current) {
      current = current.next;
      resString += current.data + " ";
    }
    return resString;
  };
}

最后

点个?希望和你交个朋友

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。