【我有一個鏈表想跟你談談~】- JS中的算法與數據結構-鏈表(Linked-list)

JS中的算法與數據結構——鏈表(Linked-list)

什麼是鏈表

如封面 ^_^
詳細點解釋的話。。那不如抄書吧
慣例,抄書交給截圖 -。-
javascript


圖片截取自[數據結構(C語言版)].嚴蔚敏_吳偉民java

實現一個鏈表

//節點類
class LinkedListNode {
    constructor(data){
        this.data = data
        this.next = null
    }
}
//鏈表類
const head = Symbol("head")
class LinkedList {
    constructor(){
        this[head] = null
    }
    //增長節點
    add(data){
        const newNode = new LinkedListNode(data)
        if (this[head] === null) {
            this[head] = newNode
        } else {
            let current = this[head]
            while(current.next){
                current = current.next
            }
            current.next = newNode
        }
    }
    //查找當前節點
    findAt(index){
        if (index > -1) {
            let current = this[head]
            let i = 0
            while(current !== null){
                if(i === index){
                    return current
                }
                current = current.next
                i++
            }
        } else {
            return undefined
        }
    }
    find(data){
        let current = this[head]
        while((current !== null) && (current.data !== data)){
            current = current.next
        }
        return current === null ? undefined : current
    }
    //查找前一個節點
    findPrevAt(index){
        if(index < 1){
            return undefined
        }
        let current = this[head]
        let previous = null
        let i = 0
        while(current !== null){
            if(i === index){
                return previous
            }
            previous = current
            current = current.next
            i++
        }
        return undefined
    }
    findPrev(data){
        let current = this[head]
        let previous = null
        while(current !== null){
            if(current.data === data){
                return previous === null ? undefined : previous
            }
            previous = current
            current = current.next
        }
        return undefined
    }
    //刪除節點
    removeAt(index){
        //邊界
        if(this[head] === null || index < 0){
            console.error('節點不存在')
            return undefined
        }
        //第一個節點
        if(index === 0){
            const node = this[head]
            this[head] = this[head].next
            return node
        }
        const current = this.findAt(index)
        const previous = this.findPrevAt(index)
        //未找到節點
        if(current === undefined){
            console.error('節點不存在')
            return undefined
        }
        //最後一個節點
        if(current.next === null){
            previous.next = null
            return current
        }
        //中間節點
        previous.next = current.next
        return current
    }
    remove(data){
        //邊界
        if(this[head] === null){
            console.error('節點不存在')
            return undefined
        }
        const current = this.find(data)
        const previous = this.findPrev(data)
        //節點未找到
        if(current === undefined){
            console.error('節點不存在')
            return undefined
        }
        //第一個節點
        if(previous === undefined){
            const node = this[head]
            this[head] = this[head].next
            return node
        }
        //最後一個節點
        if(current.next === null){
            previous.next = null
            return current
        }
        //中間節點
        previous.next = current.next
        return current
    }
    //插入節點
    insertAt(node, index){
        //在前面插入
        if(index < 0){
            const current = this[head]
            this[head] = new LinkedListNode(node)
            this[head].next = current
            return
        }
        let current = this.findAt(index)
        if(current === undefined){
            console.error('節點不存在')
            return undefined
        }
        const newNode = new LinkedListNode(node)
        newNode.next = current.next
        current.next = newNode
    }
    insert(node, data){
        let current = this.find(data)
        if(current === undefined){
            console.error('節點不存在')
            return undefined
        }
        const newNode = new LinkedListNode(node)
        newNode.next = current.next
        current.next = newNode
    }
    //可迭代
    *[Symbol.iterator](){
        let current = this[head]
        while(current !== null){
            yield current.data
            current = current.next
        }
    }
}
複製代碼

應用

//test
const list = new LinkedList()
list.add('0')
list.add('1')
list.add('2')
list.add('3')
list.add('4')
for(let i of list){
    console.log(i)
}
複製代碼

相關題目

合併兩個有序鏈表

將兩個有序鏈表合併爲一個新的有序鏈表並返回。新鏈表是經過拼接給定的兩個鏈表的全部節點組成的。node

示例:

輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4
複製代碼

題解

/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */
/** * @param {ListNode} l1 * @param {ListNode} l2 * @return {ListNode} */

const list_1 = new LinkedList()
list_1.add(1)
list_1.add(2)
list_1.add(4)
const list_2 = new LinkedList()
list_2.add(1)
list_2.add(3)
list_2.add(4)

function mergeTwoLists(l1, l2) {
    if (l1 === null) {
        return l2;
    } else if (l2 === null) {
        return l1;
    }
    let newHead = new LinkedListNode(0);
    let temp = newHead;
    while (l1 || l2) {
        if (l1 === null) {
            newHead.next = l2;
            break;
        }
        if (l2 === null) {
            newHead.next = l1;
            break;
        }
        console.log('l1',l1)
        console.log('l2',l2)
        if (l1.data <= l2.data) {
            newHead.next = l1
            newHead = newHead.next;
            l1 = l1.next;
        } else {
            newHead.next = l2;
            newHead = newHead.next;
            l2 = l2.next;
        }
    }
    return temp.next;
};

const newList = mergeTwoLists(list_1[head], list_2[head])
console.log('newList',newList) // 1->1->2->3->4->4
複製代碼

刪除鏈表中的節點(leetcode-237)

題目內容又臭又長 就是閱讀理解 本身去看吧。。。leetcode-237算法

其實就是腦筋急轉彎...很是無語bash

/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */
/** * @param {ListNode} node * @return {void} Do not return anything, modify node in-place instead. */
var deleteNode = function(node) {
    //node就是要刪除的節點 這題沒有給head 也不須要遍歷鏈表
    //將後一個節點的值賦值給要刪除的node節點
    node.val = node.next.val
    //再將後一個節點刪除 這樣就經過賦值的方式 達到了刪除node的目的
    //可憐的node.next就是個替死鬼
    node.next = node.next.next
};
複製代碼

反轉鏈表(leetcode-206)

反轉一個單鏈表數據結構

示例:ui

輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
複製代碼

進階: 你能夠迭代或遞歸地反轉鏈表。你可否用兩種方法解決這道題?this

/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */
/** * @param {ListNode} head * @return {ListNode} */
var reverseList = function(head) {
    let current = head
    let pre = null
    while(current !== null){
        let temp = current.next
        current.next = pre
        pre = current
        current = temp
    }
    return pre
};
複製代碼

鏈表的中間結點 (leetcode 876)

/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */
/** * @param {ListNode} head * @return {ListNode} */

//循環鏈表
var middleNode = function(head) {
    let A = [head];
    while (A[A.length - 1].next != null){
        A.push(A[A.length - 1].next);
    }
    return A[Math.trunc(A.length / 2)];
};

//快慢指針
var middleNode = function(head) {
    let slow = head
    let fast = head
    while(fast && fast.next){
        slow = slow.next
        fast = fast.next.next
    }
    return slow
};
複製代碼

相交鏈表(leetcode 160)

/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */

/** * @param {ListNode} headA * @param {ListNode} headB * @return {ListNode} */
//標記
var getIntersectionNode = function(headA, headB) {
    while(headA){
        headA.tag = 1
        headA = headA.next
    }
    while(headB){
        if(headB.tag){
            return headB
        }
        headB = headB.next
    }
    return null
};
//嵌套循環
var getIntersectionNode = function(headA, headB) {
    while(headA){
        let temp = headB
        while(temp){
            if(temp === headA){
                return temp
            }
            temp = temp.next
        }
        headA = headA.next
    }
    return null
};
//雙指針
var getIntersectionNode = function(headA, headB) {
    let la = headA
    let lb = headB
    while(la !== lb){
        la = la ? la.next : headB
        lb = lb ? lb.next : headA
    }
    return la
};
複製代碼

刪除排序鏈表中的重複元素(leetcode 83)

/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */
/** * @param {ListNode} head * @return {ListNode} */
var deleteDuplicates = function(head) {
    let current = head
    while(current && current.next){
        if(current.val === current.next.val){
            current.next = current.next.next
        } else {
            current = current.next
        }
    }
    return head
};
複製代碼

環形鏈表(leetcode141)

/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */

/** * @param {ListNode} head * @return {boolean} */
//標記
var hasCycle = function(head) {
    while(head){
        if(head.tag){
            return true
        }
        head.tag = 1
        head = head.next
    }
    return false
};
// JSON.stringify
var hasCycle = function(head) {
    try{
        JSON.stringify(head);
        return false;
    }
    catch(err){
        return true;
    }
}
//快慢指針
var hasCycle = function(head) {
    let slow = head
    let fast = head
    while(fast && fast.next){
        slow = slow.next
        fast = fast.next.next
        if(slow === fast){
            return true
        }
    }
    return false
};

複製代碼

移除鏈表元素(leetcode 203)

/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */
/** * @param {ListNode} head * @param {number} val * @return {ListNode} */
var removeElements = function(head, val) {
    let first = new ListNode()
    first.next = head
    let temp = first
    while(temp && temp.next){
        if(temp.next.val === val){
            temp.next = temp.next.next
        } else {
            temp = temp.next
        }
    }
    return first.next
};
//遞歸
var removeElements = function(head, val) {
    if(!head){
        return null
    }
    head.next = removeElements(head.next, val)
    if(head.val === val){
        return head.next
    } else {
        return head
    }
};
複製代碼

啊。。。spa

又挖一個坑, 未完待續 。 。 。指針

相關文章
相關標籤/搜索