数据结构学习笔记-单向链表

114 阅读2分钟

单向链表

2.png 单向链表是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量指向列表中的下一个结点;

链表是由结点构成,head指针指向第一个成为表头结点,而终止于最后一个指向NULL的指针。

链表的优点

相比较普通的线性结构,链表结构的可以总结一下:

(1)单个节点创建非常方便,普通的线性内存通常在创建的时候就需要设定数据的大小

(2)节点的删除非常方便,不需要像线性结构那样移动剩下的数据

(3)节点的访问方便,可以通过循环或者递归的方法访问到任意数据,但是平均的访问效率低于线性表

单链表的实现

function linkList() {
    function node(data) {
      this.data = data;
      this.next = null;
    }
    this.head = null;
    this.length = 0; 
}

添加节点

3.png

linkList.prototype.append = function(data) {
  // 新增节点
  let newNode = new node(data);
  // 如果链表为空
  if (this.length === 0) {
    this.head = newNode;
  } else {
    // 找到最后节点,再指向newNode
    let current = this.head;
    while (current.next) {
      current = current.next; // 循坏找到最后一个节点
    }
    current.next = newNode;
  }
  this.length += 1; 
};

insert方法

4.png

5.png

linkList.prototype.insert = function(index, data) {
  // 边界问题
  if (index < 0 || index > this.length) return false;
  let newNode = new node(data);
  // 添加的是第一个
  if (index === 0) {
    // 将newNode设置为head节点   并指向之前的head节点
    let head = this.head;
    this.head = newNode;
    newNode.next = head;
  } else {
    // 向中间添加  ----- 也满足最后一个添加
    let j = 0;
    let current = this.head;
    let pre = null;
    while (j++ < index) {     // j++ 先比较j 再+=1   ++j  先+= 1  再比较  
      pre = current; // 找到前一个节点
      current = current.next; // 找到index后一个节点
    }
    // 前一个节点指向新的节点 新的节点指向index后的一个节点
    pre.next = newNode;
    newNode.next = current;
  }
  this.length += 1;
  return true;
};

findNode方法

// 通过index找到当前的值
linkList.prototype.findNode = function(index) {
  if (index < 0 || index >= this.length) return null;
  let j = 0;
  let current = this.head;
  while (j < index) {
    // 和j++ < index 一样
    current = current.next;
    j++;
  }
  return current.data;
};

indexOf方法

// indexOf方法,通过值找到下标
linkList.prototype.IndexOf = function(data) {
  let current = this.head;
  let index = 0;
  while (current) {
    if (current.data === data) {
      return index;
    }
    current = current.next;
    index += 1;
  }
  return -1;
};

update方法

6.png

// 修改某个元素
linkList.prototype.update = function(j, data) {
  if (j < 0 || j >= this.length) return false;
  let newNode = new node(data);
  let current = this.head;
  for (let i = 0; i < this.length; i++) {
    if (i === j) {
      current.data = newNode;
    }
    current = current.next;
  }
  return true;
};
 linkList.prototype.update = function(j, data) {
  if (j < 0 || j >= this.length) return false;
  let newNode = new node(data);
  let current = this.head;
  let index = 0;
  // <j ,index++,即找到下标为j的node;
  while (index++ < j) {
    current = current.next;
  }
  current.data = newNode;
  return true;
};

removeAt()

7.png

8.png

 linkList.prototype.removeAt = function(j) {
  // 边界问题
  if (j < 0 || j >= this.length) return false;
  let current = this.head;
  if (j === 0) {
    this.head = current.next; // head的节点指向之前head的下一个节点
  } else {
    let index = 0;
    let pre = null;
    while (index++ < j) {
      pre = current;
      current = current.next;
    }
    // 删除的前一个节点指向删除的下一个节点
    pre.next = current.next;
    this.length -= 1;
    return true;
  }
};

remove方法

 // 根据data删除节点
linkList.prototype.remove = function(data) {
  let index = this.IndexOf(data); // 找到下标
  return this.removeAt(index);
};

toString方法

linkList.prototype.toString = function() {
  let current = this.head;
  let res = "";
  while (current) {
    res += current.data + " ";
    current = current.next;
  }
  return res;
};
let list = new linkList();
list.append(1);
list.append(2);
list.append(3);

// list.insert(0, 9);   // 9,1,2,3
// list.insert(1, 10);  // 1,10,2,3
// list.insert(3,100);  // 1,2,3,100,

// let node = list.findNode(0); // 1
// console.log(node, "node");
// let index = list.IndexOf(2);
// console.log(index,'index')  // 1

//   list.update1(2, 400); // 1,2,400
// list.removeAt(2);  // 1,2
//   list.remove(1);  // 2,3