我對JS鏈表的簡單學習

我對JS鏈表的學習

什麼是鏈表

要存儲多個元素,數組多是最經常使用的數據結構。這種數據結構很是方便,可是有一個缺點:從數組的起點或者中間插入或移除項的成本很是高,由於須要移動元素(好比你插入一個元素後面的全部的元素都移動了「位置」)。javascript

鏈表存儲有序的元素集合,可是不一樣於數組,鏈表中的元素在內存中並非連續放置的。每一個元素都是由一個存儲元素自己的節點和一個指向下一元素的引用(也叫指針或者連接)組成。java

單向鏈表示意圖

相比於數組來講,鏈表的好處在於添加或者刪除元素的時候不須要移動其餘元素。可是操做鏈表須要使用指針。數組的一個優勢是能夠直接訪問任何位置的任何元素,可是要是想訪問鏈表中的某一元素,則是必須從起點開始迭代直到找到目標元素。node

鏈表的學習

建立一個鏈表數組

function LinkedList() {
    var Node = function(element) {
        this.element = element;
        this.next = null;
    }

    //各類方法
}

Node表示要加入列表的項,它包含一個element屬性以及一個next屬性,element表示要添加到列表的值,next表示指向列表下一個節點項的指針。數據結構

當一個Node元素被建立時,它的next指針老是nullapp

  • 向鏈表尾部追加元素學習

列表爲空,添加的是第一個元素。列表不爲空,向其追加元素。this

要循環訪問列表中的全部元素,就須要有一個起點,就是headspa

this.append = function(element) {
    var node = new Node(element), //傳入值建立Node項
        current;

    if(head === null) { //若是爲空鏈表
        head = node; //設置node爲head(head爲第一個節點的引用)
    } else {
        current = head; //從表頭開始
        while(current.next) { 
            //循環列表,找到最後一項(列表最後一個節點的下一個元素始終是null)
            current = current.next;
        }
        //使當前最後一項的指針指向node
        current.next = node;
    }
    length++; //更新列表長度
};

使用append指針

var list = new LinkedList();
list.append(15);
list.append(10);
  • 從鏈表移除元素

輸入位置,從特定位置移除一個元素

this.removeAt = function(position) {
    if(position > -1 && position < length) { //有效性檢測
        var current = head, //用current來循環列表
        previous,
        index = 0;

        if(position === 0) {
            head = current.next; //移除第一個元素,直接把head指向下一個元素
        } else {
            while(index++ < position) { //循環列表找到知足條件的那個元素
                previous = current; //
                current = current.next; //把下一個變量覆給current
            }
            //跳過current,將當前要移除的元素的上一個與下一項直接鏈接起來。
            previous.next = current.next;
        }
        length --;
        return current.element;
    } else {
        return null;
    }
}

在任意位置插入一個元素

this.insert = function (position, element) {
    if(position >= 0 && position <= length) {
        var node = new Node(element),
            current = head; //經過current從head位置開始迭代
            previous,
            index = 0;

        if(position === 0) { //第一個位置
            node.next = current; //此時current = head,指向head那麼node就成了第一個
            head = node; //node指向爲head
        } else {
            while (index++ < position ) { //循環迭代到目標位置
                previous = current; 
                current = current.next;
            }

            node.next = current; // node的下一個爲current
            previous.next = node; // node的上一個位置爲previous
        }
        length++;
        return true;
    } else {
        return false;
    }
}

把LinkedList對象轉換成一個字符串。

this.toString = function() {
    var current = head,
        string = '';
    while(current) { //循環訪問列表
        string += current.element + (current.next ? '\n' : '');
        current = current.next;
    }
    return string; //返回字符串
}

返回元素的位置

this.indexOf = function(element) {
    var current = head,
        index = 0;
    while(current) {
        if(element === current.element) {
            return index; //找到返回當前位置
        }
        index ++;
        current = current.next;
    }
    return -1;    //找不到返回-1
}

輸入元素,移除該元素

this.remove = function(element) {
    var index = this.indexOf(element); //獲得元素的位置
    return this.removeAt(index); //移除該元素
}

判斷是否爲空 獲得長度 獲得第一個元素

this.isEmpty = function () {
    return length === 0;
}

this.size = function () {
    return length;
}

this.getHead = function () {
    return head;
}

雙向鏈表

  • 他和普通鏈表的區別,在雙向鏈表中,連接是雙向的,一個鏈向下一個元素一個鏈向上一個元素。在操做雙向鏈表的時候既要像普通鏈表同樣考慮next,也要考慮prev。

雙向列表提供了兩種迭代列表的方法:從頭至尾迭代,或者反過來。

  • 建立一個雙向列表

function DoublyLinkedList() {
    var Node = function(element) {
        this.element = element;
        this.next = null;
        this.prev = null; //新指針
    };
    
    var length = 0;
    var head = null;
    var tail = null; //對列表最後一項的引用
    
    //各類方法
}
  • 在任意位置插入一個新元素

this.insert = function(position, element) {
    if(position >= 0 && position <= length) {
        var node = new Node(element),
            current = head,
            previous,
            index = 0;
            
        if(position === 0) { //在第一個位置添加
            if(!head) { //若是head不存在即鏈表爲空
                head = node;
                tail = node;
            } else { //鏈表不爲空
                node.next = current;
                current.prev = node;
                head = node;
            }
        } else if(position === length) { //在最後一個位置添加
            current = tail;
            current.next = node;
            node.prev = current;
            tail = node;
        } else {
            while(index++ < position) { //在列表中間添加
                previous = current; //循環迭代
                current = current.next;
            }
            node.next = current;
            previous.next = node;
            
            current.prev = node;
            node.prev = previous;
        }
        length ++; //更新列表長度
        
        return true;
    } else {
        return false;
    }
}
  • 從任意位置移除元素

this.removeAt = function(position) {
    if(position > -1 && position < length) { //檢查越界值
        var current = head,
            previous,
            index = 0;
        if(position === 0) { //第一個位置
            head = current.next;
            
            if(length === 1) { //若是鏈表只有一項
                tail = null;
            } else { //也就至關於把current.next.prev = null
                head.prev = null;
            }
        } else if(position === length -1) { //最後一項
            current = tail; //tail的引用賦給current變量
            tail = current.prev; //上一項指向tail
            tail.next = null; //最後一項的next都是指向null的
        } else {
            while(index++ < position) { //從中間位置移除
                previous = current;
                current = current.next;
            }
            
            previous.next = current.next; //直接跳過current鏈接上一項和下一項
            current.next.prev = previous;
        }
        length --;
        return current.element;
    } else {
        return null;
    }
}

循環鏈表

  • 單向循環鏈表和鏈表惟一去別在於:最後一個元素指向下一個元素的指針(tail.next)不是引用null而是指向第一個元素(head)

  • 雙向循環鏈表有指向head的tail.next,也有指向tail的head.prev

雙向循環鏈表示意圖

相關文章
相關標籤/搜索