1. 程式人生 > >js實現資料結構—連結串列

js實現資料結構—連結串列

一、單鏈表建構函式

function LinkedList() {

    /**
     * 資料節點建構函式
     *
     * @param {*} data
     */
    function Node(data) {
        this.data = data;
        this.next = null;
    }

    let length = 0;

    let head = null;
    let tail = null;

    /**
     * 連結串列尾部追加資料
     *
     * @param {*} item
     */
    this.append = function (item) {

        const newNode = new Node(item);

        if (0 < length) {
            tail.next = newNode;
            tail = newNode;
        } else {
            head = tail = newNode;
        }

        length++;

    };

    /**
     * 在指定索引位置的前面插入資料
     *
     * @param {number} index 指定的索引位置
     * @param {*} item
     * @returns {boolean} 返回是否成功
     */
    this.insert = function (index, item) {

        if (0 <= index && index <= length) {

            const newNode = new Node(item);

            if (0 < index && index < length) {

                // 在中間新增
                let prevNode = null;
                let targetNode = head;

                let prevIndex = 0;
                while ((prevIndex++) < index) {
                    prevNode = targetNode;
                    targetNode = targetNode.next;
                }

                prevNode.next = newNode;
                newNode.next = targetNode;

            } else if (0 === index) {

                // 在頭部新增
                newNode.next = head;
                head = newNode;

            } else {

                // 在尾部新增
                this.append(item);

            }

            length++;

            return true;

        } else {

            return false;

        }

    };

    /**
     * 刪除指定索引位置處的資料項。發生錯誤將throw一個Error
     *
     * @param {number} index 指定的索引位置
     * @returns {*} 返回被刪除的資料
     */
    this.remove = function (index) {

        if (0 <= index && index < length) {

            let targetNode;

            if (0 < index) {

                // 刪除非頭部
                let prevNode = null;
                targetNode = head;

                let prevIndex = 0;
                while ((prevIndex++) < index) {
                    prevNode = targetNode;
                    targetNode = targetNode.next;
                }

                prevNode.next = targetNode.next;
                targetNode.next = null;

                // 如果刪除的是最後一個,把tail指向倒數第二個
                if ((1 + index) === length) {
                    tail = prevNode;
                }

            } else if (0 === index) {

                targetNode = head;

                // 刪除頭部
                const nextNode = targetNode.next;
                targetNode.next = null;

                head = nextNode;

            }

            length--;

            return targetNode.data;

        } else {

            throw new RangeError(`out of range: must between 0 and ${length}`);

        }

    };

    /**
     * 查詢資料項在連結串列中的索引位置
     *
     * @param {*} item
     * @returns {number} 索引位置,不存在則返回-1
     */
    this.indexOf = function (item) {

        let prevIndex = 0;

        let targetNode = head;
        while (!!targetNode) {
            if (item !== targetNode.data) {
                targetNode = targetNode.next;
                prevIndex++;
            } else {
                return prevIndex;
            }
        }

        return -1;

    };

    /**
     * 順序打印出連結串列中的所有節點資料
     *
     */
    this.print = function () {

        let index = 0;

        let targetNode = head;
        while (!!targetNode) {
            console.log('[', index++, ']=>', targetNode.data);
            targetNode = targetNode.next;
        }

    };

    /**
     * 查詢單鏈表中的第K個節點
     *
     * @param {number} index 索引位置
     * @returns {*} index位置的資料
     */
    this.findByIndex = function (index) {

        if (0 <= index && index < length) {

            let targetNode = head;
            while (0 < (index--)) {
                targetNode = targetNode.next;
            }

            return targetNode.data;

        } else {
            throw new RangeError(`out of range: must between 0 and ${length}`);
        }

    };

    /**
     * 查詢單鏈表的中間位置的節點
     *
     * @returns {*} index位置的資料
     */
    this.findMiddle = function () {

        const index = Math.round(length / 2) - 1;

        return this.findByIndex(index);

    };

}

二、實現雙向連結串列的建構函式

function DoubleLinkedList() {
    let length=0,
        head=null,
        tail=null;


    /**
     * 資料節點建構函式
     *
     * @param {*} data
     */
    function Node(data) {

        this.data=data;
        this.next=null;
        this.previous=null;
    }

    /**
     * 連結串列尾部追加資料
     *
     * @param {*} item
     */
    this.append = function (item) {
        let newNode=new Node(item);
        //空連結串列
        if(null===head){
            head=newNode;
            tail=head;
        }else{
            tail.next=newNode;
            tail=newNode;
        }
        length++;
    };

    /**
     * 在指定索引位置的前面插入資料
     *
     * @param {number} index 指定的索引位置
     * @param {*} item
     */
    this.insert = function (index, item) {
        let newNode=new Node(item),
            current=head,
            previous=null,
            insetIndex=0;

        if(index < 0 || index > length){
            return false
        }else {
            //在第一個位置新增
            if(0 === index){
                newNode.next=current;
                current.previous=newNode;
                head=newNode
            }else if(index === index){
                //在末尾新增
                current=tail;
                current.next=newNode;
                newNode.previous=current;
                tail=newNode;
            }else {

                while (insetIndex < index){
                    previous=current;
                    current=current.next;
                    insetIndex++;
                }
                previous.next=newNode;
                newNode.previous=previous;
                newNode.next=current;
                current.previous=newNode;

            }
            length++;

        }
    };

    /**
     * 刪除指定索引位置處的資料項
     *
     * @param {number} index 指定的索引位置
     */
    this.remove = function (index) {
        if (0 <= index && index < length) {
            let targetNode;
            if (0 < index) {
                // 刪除非頭部
                let prevNode = null;
                targetNode = head;
                let prevIndex = 0;
                while ((prevIndex++) < index) {
                    prevNode = targetNode;
                    targetNode = targetNode.next;
                }
                prevNode.next = targetNode.next;
                if (!!targetNode.next) {
                    targetNode.next.prev = prevNode;
                }
                targetNode.prev = null;
                targetNode.next = null;
                // 如果刪除的是最後一個,把tail指向倒數第二個
                if ((1 + index) === length) {
                    tail = prevNode;
                }
            } else if (0 === index) {
                targetNode = head;
               // 刪除頭部
                const nextNode = targetNode.next;
                nextNode.prev = null;
                head = nextNode;
                targetNode.next = null;
            }
            length--;
            return targetNode.data;

        } else {

            throw new RangeError(`out of range: must between 0 and ${length}`);
        }
    };
    /**
     * 順序打印出連結串列中的所有節點資料
     *
     */
     this.print = function () {

        console.log('順序列印');

        let index = 0;

        let targetNode = head;
        while (!!targetNode) {
            console.log('[', index++, ']=>', targetNode.data);
            targetNode = targetNode.next;
        }

    };

    /**
     * 逆序打印出連結串列中的所有節點資料
     *
     */
     this.reversePrint = function () {

        console.log('逆序列印');

        let index = length - 1;

        let targetNode = tail;
        while (!!targetNode) {
            console.log('[', index--, ']=>', targetNode.data);
            targetNode = targetNode.prev;
        }

    };
}