数据结构之链表

1. 单向链表

链表的每个节点对象保存着链表元素和指向下一个节点的引用。如果要查找某个元素,必须从链表的第一个节点开始遍历查找,直到找到目标元素位置。

  1. push(element) 向链表后端添加元素
  2. insert(element, position) 向某个位置插入元素
  3. getElementAt(index) 获取某个位置的元素
  4. remove(element) 从链表中移除元素
  5. indexOf(element) 获取元素的位置索引
  6. removeAt(index) 移除某个位置上的元素
  7. size() 获取元素个数
  8. isEmpty() 链表是否为空
// 节点对象
class Node {
  constructor(element) {
    this.element = element;
    this.next = null;
  }
}

// 默认判断节点是否相等的函数
const defaultEqualFn = (a, b) => {
  return a === b;
}

class LinkedList {
  constructor(equalFn = defaultEqualFn) {
    this.head = null;
    this.count = 0;
    this.equalFn = equalFn;
  }

  // 添加在末端元素
  push(element) {
    let node = new Node(element);
    if (this.head === null) {
      this.head = node;
    }
    else {
      let currentNode = this.head;
      while (currentNode.next !== null) {
        currentNode = currentNode.next;
      }
      currentNode.next = node;
    }
    this.count++;
  }

  // 移除某个位置的元素
  removeAt(index) {
    if (index >= 0 && index < this.count) {
      var currentNode = this.head;
      if (index === 0) {
        this.head = currentNode.next;
      }
      else {
        let previous;
        for(let i = 0; i < index; i++) {
          previous = currentNode;
          currentNode = currentNode.next;
        }
        previous.next = currentNode.next;
      }

      this.count--;
      return currentNode;
    }
    return undefined
  }

  remove(element) {
    if (this.isEmpty()) return undefined;

    let currentNode = this.head;
    let previous = this.head;

    while (!this.equalFn(element, currentNode.element)) {
      previous = currentNode;
      currentNode = currentNode.next;
    }
    previous.next = currentNode.next;
    this.count--;
    return currentNode;
  }

  // 获取某个位置上的元素
  getElementAt(index) {
    if (index >= 0 && index < this.count) {
      let currentNode = this.head;
      for (let i = 0; i < index; i++) {
        currentNode = currentNode.next;
      }
      return currentNode;
    }

    return undefined;
  }

  // 获取某个元素的索引
  indexOf(element) {
    if (this.isEmpty()) return undefined;

    let currentNode = this.head;
    let i = 0;
    while (currentNode && !this.equalFn(element, currentNode.element)) {
      currentNode = currentNode.next;
      i++;
    }
    if (!currentNode) {
      return -1;
    }
    return i;
  }

  // 在某个位置插入元素
  insert(element, position) {
    if (position >= 0 && position <= this.count) {
      let node = new Node(element);
      let currentNode = this.head;
      let previous = this.head;
      for (let i = 0; i < position; i++) {
        previous = currentNode;
        currentNode = currentNode.next;
      }
      previous.next = node;
      node.next = currentNode;
      this.count++;
      return true;
    }
    return false;
  }

  size() {
    return this.count;
  }

  isEmpty() {
    return this.size() === 0;
  }

  toString() {
    if (this.isEmpty()) return '';
    let currentElementStr = this.head.element;
    let currentNode = this.head;


    while (currentNode.next !== null) {
      currentNode = currentNode.next;
      currentElementStr = `${currentElementStr}, ${currentNode.element}`
    }
    return currentElementStr;
  }
}

let linkedList = new LinkedList();

linkedList.push('Alice');
linkedList.push('Bob');
linkedList.insert('Jack', 1);
linkedList.insert('Vivian', 2);
linkedList.remove('Bob');
linkedList.removeAt('2');
console.log('getElementAt', linkedList.getElementAt(1).element);
console.log('indexOf', linkedList.indexOf('Jack'))
console.log(linkedList.toString());
console.log('isEmpty', linkedList.isEmpty());
console.log('size:', linkedList.size())

2. 双向链表

双向链表是单向链表的扩展,链表的节点上保存着元素、指向下一个节点的引用以及指向上一个节点的引用。

// 双向链表
class DoubleNode extends Node {
  constructor(element) {
    super(element);
    this.prev = null;
  }
}

class DoubleLinkedList extends LinkedList {
  constructor(equalFn = defaultEqualFn) {
    super(equalFn);
    this.tail = null;
  }

  push(element) {
    const node = new DoubleNode(element);

    if (this.isEmpty()) {
      this.head = node;
    }
    else {
      let currentNode = this.head;
      while (currentNode.next !== null) {
        currentNode = currentNode.next;
      }
      node.prev = currentNode;
      currentNode.next = node;
    }
    this.tail = node;
    this.count++;
  }

  insert(element, position) {
    if (position >= 0 && position <= this.count) {
      const node = new DoubleNode(element);
      let currentNode = this.getElementAt(position);

      if (currentNode === undefined) {
        this.push(element);
      }
      else if (currentNode.prev === null) {
        this.head.prev = node;
        node.next = this.head;
        this.head = node;
      }
      else {
        let prevNode = currentNode.prev;
        prevNode.next = node;
        currentNode.prev = node;
        node.prev = prevNode;
        node.next = currentNode;
      }
      this.count++;
    }
  }

  removeAt(index) {
    if (index >= 0 && index < this.count) {
      const currentNode = this.getElementAt(index);
      if (currentNode.prev === null) {
        this.head = currentNode.next;
        this.head.prev = null;
      }
      else if (currentNode.next === null) {
        this.tail = currentNode.prev;
        this.tail.next = null;
      }
      else {
        const prevNode = currentNode.prev;
        const nextNode = currentNode.next;
        prevNode.next = nextNode;
        nextNode.prev = prevNode;
      }
      this.count--;
      return currentNode;
    }
    return undefined;
  }

  remove(element) {

    const index = this.indexOf(element);
    console.log(
      'index', index
    )
    if (index === -1) return undefined;
    return this.removeAt(index);
  }
}

let doubleLinkedList = new DoubleLinkedList();

doubleLinkedList.push('Alice');
doubleLinkedList.push('Bob');
doubleLinkedList.insert('Jack', 1);
doubleLinkedList.insert('Vivian', 2);
doubleLinkedList.remove('Bob');
doubleLinkedList.removeAt('2');
console.log('getElementAt', doubleLinkedList.getElementAt(1).element);
console.log('indexOf', doubleLinkedList.indexOf('Jack'))
console.log(doubleLinkedList.toString());
console.log('isEmpty', doubleLinkedList.isEmpty());
console.log('size:', doubleLinkedList.size())

3. 循环链表

循环链表可以是单向链表也可以是双向链表。

  1. 单向链表:最后一个节点的next属性指向第一个节点。
  2. 双向链表:最右一个节点的next属性指向第一个节点,第一个节点的prev属性指向最后一个节点。

以单向列表为例

class CircularLinkedList extends LinkedList {
  constructor(equalFn = defaultEqualFn) {
    super(equalFn);
  }

  push(element) {
    const node = new Node(element);
    if (this.isEmpty()) {
      this.head = node;
      this.head.next = this.head;
    }
    else {
      let currentNode = this.head;
      for (let i = 1; i < this.count - 1; i++) {
        currentNode = currentNode.next;
      }
      node.next = this.head;
      currentNode.next = node;
    }
    this.count++;
  }

  insert(element, position) {
    if (position < 0 || position > this.count) return false;

    const node = new Node(element);
    if (position === 0) {
      let currentNode = this.head;
      for (let i = 1; i < this.count - 1; i++) {
        currentNode = currentNode.next;
      }
      currentNode.next = node;
      node.next = this.head;
      this.head = node;
      this.count++;
    }
    else if (position === this.count) {
      this.push(element);
    }
    else {
      super.insert(element, position);
    }

  }

  removeAt(index) {
    if (index < 0 || index >= this.count) return undefined;
    let result = undefined;
    if (this.count === 1) {
      result = this.head;
      this.head = null;
      this.count--;
    }
    else if (index === 0) {
      result = this.head;
      const tailNode = this.getElementAt(this.count - 1);
      this.head = this.head.next;
      tailNode.next = this.head;
      this.count--;
    }
    else if (index === this.count - 1) {
      const tailNode = this.getElementAt(this.count - 2);
      tailNode.next = this.head;
      this.count--;
    }
    else {
      result = super.removeAt(index);
    }

    return result;
  }

  remove(element) {

    const index = this.indexOf(element);
    if (index === -1) return undefined;
    return this.removeAt(index);
  }

  toString() {
    if (this.isEmpty()) return '';
    let currentElementStr = this.head.element;
    let currentNode = this.head;
    let i = 0;
    while (this.count - 1 > i) {
      currentNode = currentNode.next;
      currentElementStr = `${currentElementStr}, ${currentNode.element}`;
      i++;
    }
    return currentElementStr;
  }
}

let circularLinkedList = new CircularLinkedList();

circularLinkedList.push('Alice');
circularLinkedList.push('Bob');
circularLinkedList.insert('Jack', 1);
circularLinkedList.insert('Vivian', 2);
circularLinkedList.remove('Bob');
circularLinkedList.removeAt('2');
console.log(circularLinkedList.toString());
console.log('getElementAt', circularLinkedList.getElementAt(2).element);
console.log('indexOf', circularLinkedList.indexOf('Jack'))
console.log('isEmpty', circularLinkedList.isEmpty());
console.log('size:', circularLinkedList.size());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的纺织品企业财务管理系统,源码+数据库+毕业论文+视频演示 在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以,对纺织品企业财务信息管理的提升,也为了对纺织品企业财务信息进行更好的维护,纺织品企业财务管理系统的出现就变得水到渠成不可缺少。通过对纺织品企业财务管理系统的开发,不仅仅可以学以致用,让学到的知识变成成果出现,也强化了知识记忆,扩大了知识储备,是提升自我的一种很好的方法。通过具体的开发,对整个软件开发的过程熟练掌握,不论是前期的设计,还是后续的编码测试,都有了很深刻的认知。 纺织品企业财务管理系统通过MySQL数据库与Spring Boot框架进行开发,纺织品企业财务管理系统能够实现对财务人员,员工,收费信息,支出信息,薪资信息,留言信息,报销信息等信息的管理。 通过纺织品企业财务管理系统对相关信息的处理,让信息处理变的更加的系统,更加的规范,这是一个必然的结果。已经处理好的信息,不管是用来查找,还是分析,在效率上都会成倍的提高,让计算机变得更加符合生产需要,变成人们不可缺少的一种信息处理工具,实现了绿色办公,节省社会资源,为环境保护也做了力所能及的贡献。 关键字:纺织品企业财务管理系统,薪资信息,报销信息;SpringBoot
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值