javascript 链表(lineked lists)算法与说明
2017-09-13 00:28
393 查看
链表的介绍
链表存储有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称为指针或链接)组成。下图讲解:相对于传统的数组,链表的一个好处在于,添加或移除元素的时候不需要移动其他元素。然而,链表需要使用指针,因此实现链表的时候需要注意。数组的另一个细节是可以直接访问任何位置元素,而要想访问链表中间的一个元素,需要从起点(表头)开始送达列表直到找到所需要元素。
现实实例就是火车,火车有多节车厢相互衔接,通过接轨来链接火车。车厢就是链表的元素,而接轨就是指针。
链表算法实例
1.链表增删改查。let list = new LinkedList(); list.append(15); list.append(10); list.append(13);//15,10,13 list.indexOf(10);//1 list.removeAt(1)//15,13 list.insert(1,17);//15,17,13 list.remove(11);//17,13
ES6链表实现代码:
let LinkedList = (function () { class Node {//一个节点 constructor(element){ this.element = element; this.next = null; } } const length = new WeakMap(); const head = new WeakMap(); class LinkedList { constructor () { length.set(this, 0); head.set(this, null); } append(element) {//向列表尾部添加一个新的项 let node = new Node(element), current; if (this.getHead() === null) { head.set(this, node); } else { current = this.getHead(); while (current.next) { current = current.next; } current.next = node; } let l = this.size(); l++; length.set(this, l); } insert(position, element) {//向列表的特定位置插入一个新的项 if (position >= 0 && position <= this.size()) { let node = new Node(element), current = this.getHead(), previous, index = 0; if (position === 0) { node.next = current; head.set(this, node); } else { while (index++ < position) { previous = current; current = current.next; } node.next = current; previous.next = node; } let l = this.size(); l++; length.set(this, l); return true; } else { return false; } } removeAt(position) {//从列表的特定位置移除一项 if (position > -1 && position < this.size()) { let current = this.getHead(), previous, index = 0; if (position === 0) { head.set(this, current.next); } else { while (index++ < position) { previous = current; current = current.next; } previous.next = current.next; } let l = this.size(); l--; length.set(this, l); return curren 4000 t.element; } else { return null; } } remove(element) {//移除一项 let index = this.indexOf(element); return this.removeAt(index); } indexOf(element) {//返回元素在列表中的索引,没有返回-1 let current = this.getHead(), index = 0; while (current) { if (element === current.element) { return index; } index++; current = current.next; } return -1; } isEmpty() {//链表不包含任何元素,返回true,如果长度大于0返回false return this.size() === 0; } size() {//返回链表包含的元素个数 return length.get(this); } getHead() {//获取链头项 return head.get(this); } toString() {//已string输出链表 let current = this.getHead(), string = ''; while (current) { string += current.element + (current.next ? ', ' : ''); current = current.next; } return string; } print() {//string格式打印到控制台上。 console.log(this.toString()); } } return LinkedList; })();
双向链表
双向链表和普通链表的区别在于。在链表中,一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的:一个链向下一个元素,另一个链向前一个元素。如下图:双向链表提供了两种送代列表的方法:从头到尾,或者反过来。我们也可以访问一个特定节点的下一个或前一个元素。在单向链表中,如果送代列表时错过了要找的元素,就需要回到列表起点,重新开始送代。这是双向链表的一个优点。
事例:
let list = new DoublyLinkedList(); list.append(15); list.append(16);//15,16 list.print();//15,16 list.printInverse();//16, 15 list.insert(0,13);//13,15,16 list.removeAt(0);//15,16
ES6代码实例:
let DoublyLinkedList = (function () { class Node { constructor(element) { this.element = element; this.next = null; this.prev = null; //NEW } } const length = new WeakMap(); const head = new WeakMap(); const tail = new WeakMap(); //NEW class DoublyLinkedList { constructor () { length.set(this, 0); head.set(this, null); tail.set(this, null); } append(element) { let node = new Node(element), current, _tail; if (this.getHead() === null) { //first node on list head.set(this, node); tail.set(this, node); //NEW } else { //attach to the tail node //NEW _tail = this.getTail(); _tail.next = node; node.prev = _tail; tail.set(this, node); } //update size of list let l = this.size(); l++; length.set(this, l); } insert(position, element) { //check for out-of-bounds values if (position >= 0 && position <= this.size()) { let node = new Node(element), current = this.getHead(), previous, index = 0; if (position === 0) { //add on first position if (!this.getHead()) { //NEW head.set(this, node); tail.set(this, node); } else { node.next = current; current.prev = node; //NEW {1} head.set(this, node); } } else if (position === this.size()) { //last item //NEW current = tail; // {2} current.next = node; node.prev = current; tail.set(this, node); } else { while (index++ < position) { //{3} previous = current; current = current.next; } node.next = current; previous.next = node; current.prev = node; //NEW node.prev = previous; //NEW } //update size of list let l = this.size(); l++; length.set(this, l); return true; } else { return false; } } removeAt(position) { //check for out-of-bounds values if (position > -1 && position < this.size()) { let _head = this.getHead(), _tail = this.getTail(), current = _head, previous, index = 0; //removing first item if (position === 0) { _head = current.next; // {1} //if there is only one item, then we update tail as well //NEW if (this.size() === 1) { // {2} _tail = null; } else { _head.prev = null; // {3} } } else if (position === this.size() - 1) { //last item //NEW current = _tail; // {4} _tail = current.prev; _tail.next = null; } else { while (index++ < position) { // {5} previous = current; current = current.next; } //link previous with current's next - skip it to remove previous.next = current.next; // {6} current.next.prev = previous; //NEW } head.set(this,_head); tail.set(this,_tail); //update size of list let l = this.size(); l--; length.set(this, l); return current.element; } else { return null; } } remove(element) { let index = this.indexOf(element); return this.removeAt(index); } indexOf(element) { let current = this.getHead(), index = -1; //check first item if (element == current.element) { return 0; } index++; //check in the middle of the list while (current.next) { if (element == current.element) { return index; } current = current.next; index++; } //check last item if (element == current.element) { return index; } return -1; } isEmpty() { return this.size() === 0; } size() { return length.get(this); } toString() { let current = this.getHead(), s = current ? current.element : ''; while (current && current.next) { current = current.next; s += ', ' + current.element; } return s; } inverseToString() { let current = this.getTail(), s = current ? current.element : ''; while (current && current.prev) { current = current.prev; s += ', ' + current.element; } return s; } print() { console.log(this.toString()); } printInverse() { console.log(this.inverseToString()); } getHead() { return head.get(this); } getTail() { return tail.get(this); } } return DoublyLinkedList; })();
循环链表
循环链表。就是最后一个元素指向不是null,而是指向第一个元素(head)。如下图。实例用法:
let circularLinkedList = new CircularLinkedList(); circularLinkedList.append(15); circularLinkedList.append(16);//15,16 circularLinkedList.insert(0,14);//14,15,16 circularLinkedList.removeAt(0);//15,16 circularLinkedList.indexOf(16)//1
ES6循环链表实例:
let CircularLinkedList = (function () { class Node { constructor(element) { this.element = element; this.next = null; } } const length = new WeakMap(); const head = new WeakMap(); class CircularLinkedList { constructor () { length.set(this, 0); head.set(this, null); } append(element) { let node = new Node(element), current; if (this.getHead() === null) { //first node on list head.set(this, node); } else { current = this.getHead(); //loop the list until find last item while (current.next !== this.getHead()) { //last element will be head instead of NULL current = current.next; } //get last item and assign next to added item to make the link current.next = node; } //set node.next to head - to have circular list node.next = this.getHead(); //update size of list let l = this.size(); l++; length.set(this, l); } insert(position, element) { //check for out-of-bounds values if (position >= 0 && position <= this.size()) { let node = new Node(element), current = this.getHead(), previous, index = 0; if (position === 0) { //add on first position node.next = current; //update last element while (current.next !== this.getHead()) { //last element will be head instead of NULL current = current.next; } head.set(this, node); current.next = this.getHead(); } else { while (index++ < position) { previous = current; current = current.next; } node.next = current; previous.next = node; } //update size of list let l = this.size(); l++; length.set(this, l); return true; } else { return false; } } removeAt(position) { //check for out-of-bounds values if (position > -1 && position < this.size()) { let current = this.getHead(), previous, index = 0; //removing first item if (position === 0) { while (current.next !== this.getHead()) { //needs to update last element first current = current.next; } head.set(this, this.getHead().next); current.next = this.getHead(); } else { //no need to update last element for circular list while (index++ < position) { previous = current; current = current.next; } //link previous with current's next - skip it to remove previous.next = current.next; } let l = this.size(); l--; length.set(this, l); return current.element; } else { return null; } } remove(element) { let index = indexOf(element); return removeAt(index); } indexOf(element) { let current = this.getHead(), index = -1; //check first item if (element == current.element) { return 0; } index++; //check in the middle of the list while (current.next !== this.getHead()) { if (element == current.element) { return index; } current = current.next; index++; } //check last item if (element == current.element) { return index; } return -1; } isEmpty() { return this.size() === 0; } size() { return length.get(this); } getHead() { return head.get(this); } toString() { let current = this.getHead(), s = current.element; while (current.next !== this.getHead()) { current = current.next; s += ', ' + current.element; } return s.toString(); } print() { console.log(this.toString()); } } return CircularLinkedList; })();
相关文章推荐
- 密码强度检测算法分析及实现(JavaScript)案例说明
- javascript 红黑树算法与说明
- JavaScript数据结构与算法之链表
- javascript 散列表(Hashes)算法与说明
- JavaScript中数据结构与算法(三):链表
- JavaScript中数据结构与算法(三):链表
- JavaScript数据结构与算法Item4--链表
- 前端常见算法面试题之 - 从尾到头打印链表[JavaScript解法]
- 怎样编写一个程序,把一个有序整数数组放到二叉树中? 编写实现链表排序的一种算法。说明为什么你会选择用这样的方法?
- javascript 队列(queue)算法与说明
- javascript 字典(dictionary)算法与说明
- javascript校验身份证,获取生日、性别、年龄和身份证算法说明
- javascript 图(Graphs)算法与说明
- javascript 排序(Sorting)算法与说明
- javascript校验身份证,获取生日、性别、年龄和身份证算法说明
- javascript算法-单链表
- javascript 集合(set)算法与说明
- 数据结构与算法JavaScript - 链表
- javascript数据结构与算法--链表
- 79 1.编写实现链表排序的一种算法。说明为什么你会选择用这样的方法?