---
# System prepended metadata

title: '資料結構 part 2: Linked list, stack & queue and hashtable'
tags: [資料結構, data strcuture]

---

資料結構 part 2: Linked list, stack & queue and hashtable
===
![](https://i.imgur.com/8VcJihJ.jpg)

---

###### tags: `data strcuture`, `資料結構`

這篇的筆記主要來自於 Wilson Ren 的[資料結構與演算法](https://www.udemy.com/course/algorithm-data-structure/#instructor-1)課程以及[JavaScript 資料結構與演算法](https://www.books.com.tw/products/0010805943#:~:text=%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B%EF%BC%88data%20structure%EF%BC%89%E6%98%AF,%E9%9B%86%E5%90%88%E5%87%BD%E6%95%B8%E8%88%87%E9%9B%9C%E6%B9%8A%E8%A1%A8%E3%80%82)


# Linkedin List 鏈結串列
「陣列」是程式語言中最常見的存放資料序列的資料結構，但「陣列」的缺點是：**大小固定，移動成本高**。

相較於「陣列」，「鏈結串列」內的元素，不同於「陣列」在記憶體內是連續存放的，而「鏈結序列」則是：
1. **不是連續存放**。
2. 由 **元素本身的節點(這裡的元素可以是：字串、數字、陣列或任何)和指向下一個元素的引用(指位器或鏈結)** 組成。
3. 包含起點(head)和長度(length)。
4. 長度均由 0 開始，視插入多少 node 來計算最終長度。(但陣列是一開始要先定義好長度)

![](https://i.imgur.com/CQSM96D.png)

## Pros
- 「鏈結序列」在新增或移除時，不需要移動其他元素。假設要刪除 "Jake"，只需要把 "Allen" 的指位器指向 "Kelvin" 就好。

![](https://i.imgur.com/lepGyDQ.png)


> 陣列：可以直接存取任一位置的任何元素。


## Cons
- 「鏈結序列」若要存取中間位置的元素，則需要從起點(head)開始迭代直到找到為止。
- 由於使用指位器，所需的記憶體較陣列多。
- 由於是不連續存放元素，若序列越大，要存取某位置的元素時，時間會花費越多。
- 反向遍歷的操作上會顯得較為困難。

> 陣列：
> - 新增元素：會不斷擴大電腦所需記憶體，假設有一個陣列的長度為 4，當該陣列滿了，想要再增加第 5 個元素的話，電腦就會額外建立 4 個記憶體空間，以此類推。

![](https://i.imgur.com/fAyWSp5.png)


> - 刪除元素：當刪除陣列的任一位置的元素時，後面的元素都必須逐一往前遞補。

![](https://i.imgur.com/npp3VqR.png)

---
## linked list push

增加資料會考慮到的事情：
1. 如果新增的資料為第一個資料，代表後續沒有其他資料，那麽新增加的節點就會是 `head = null`，`length = 0`。
2. 如果不是第一個，那麼就要設定當前位置為 `head`，透過迴圈來遍歷每一個節點，如果不為 `null`，就把當前位置的節點設定為下一個節點，直到最後，再將最後一個節點的下一個指向新的 `node`，然後 `length` 在上述作業完後加一。



```javascript=
// create node
class Node {
    constructor(value) {
        this.value = value;
        this.next = null;
    }
}

// create linked list
class LinkedList {
    constructor() {
        this.head = null;
        this.length = 0;
    }
    
    // create a push func
    push(value) {
        let newNode = new Node(value)
        // If nothing in linked list, newNode would be the head
        if (this.head === null) {
            this.head = newNode;
        } else {
            // if something inside the linked list, then we need to find 
            // the current position 
            let currentNode = this.head;
            
            // use while loop to loop thr, if it's not null, 
            // value of currentNode would be the next value
            while(currentNode.next !== null) {
                currentNode = currentNode.next;
            }
            // otherwise, the next vlaue of currentNode would the new one.
            currentNode.next = newNode;
        }
        this.length++;
    }
    // create a func that can print out all nodes
    printAll() {
        if (this.length === 0) {
            console.log("0");
            return 
        }
        let currentNode = this.head;
        while(currentNode !== null) {
            console.log(currentNode.value);
            currentNode = currentNode.next;
        }
    }
}

let myLinkedList = new LinkedList()
myLinkedList.push("Mike");
myLinkedList.push("Allen");
myLinkedList.push("Jake");
myLinkedList.push("Kelvin");

myLinkedList.printAll();
console.log(myLinkedList.length)
```

![](https://i.imgur.com/6vfWIAh.png)

---

## linked list pop

刪除資料會需要考慮到的事情：
1. 如果該鏈結串列內的資料的 `head` 不存在，就返回 `null`。
2. 如果長度等於 1 表示只有 `head`，那麼 `head = null`，`length = 0`，但因為 `pop()` 會返回刪除的值，因此我們必須將 `head` 存在另外一個變數，然後返回該變數。
3. 刪除最後的值，必須要遍歷到倒數第二個，因為只要將倒數第二個的 pointer 設定為 `null`，長度減一即可。假設長度為 `k`，那麼倒數第二個位置則為 `k-2`


![](https://i.imgur.com/GSq24To.png)

![](https://i.imgur.com/rvQveX5.png)

```javascript=
// create node
class Node {
    constructor(value) {
        this.value = value;
        this.next = null;
    }
}

// create linked list
class LinkedList {
    constructor() {
        this.head = null;
        this.length = 0;
    }
    
    // create a push func
    push(value) {
        let newNode = new Node(value)
        // If nothing in linked list, newNode would be the head
        if (this.head === null) {
            this.head = newNode;
        } else {
            // if something inside the linked list, then we need to find 
            // the current position 
            let currentNode = this.head;
            
            // use while loop to loop thr, if it's not null, 
            // value of currentNode would be the next value
            while(currentNode.next !== null) {
                currentNode = currentNode.next;
            }
            // otherwise, the next vlaue of currentNode would the new one.
            currentNode.next = newNode;
        }
        this.length++;
    }
    pop() {
        if(!this.head) {
            return null;
        } else if (this.length === 1) {
            let temp = this.head;
            this.head = null;
            this.length = 0;
            return temp;
        } else {
            // loop thr all the node
            // create a current position
            let currentNode = this.head;
            for (let steps = 1; steps <= length -2; steps++) {
                currentNode = currentNode.next;
            }
            let temp = currentNode.next;
            currentNode.next = null;
            this.length --;
            return temp;
        }
    }
    // create a func that can print out all nodes
    printAll() {
        if (this.length === 0) {
            console.log("0");
            return 
        }
        let currentNode = this.head;
        while(currentNode !== null) {
            console.log(currentNode.value);
            currentNode = currentNode.next;
        }
    }
}

let myLinkedList = new LinkedList()
myLinkedList.push("Mike");
myLinkedList.push("Allen");
myLinkedList.push("Jake");
myLinkedList.push("Kelvin");
let poppedValue = myLinkedList.pop();
console.log(poppedValue);
myLinkedList.printAll();
console.log(myLinkedList.length)


// Node { value: 'Kelvin', next: null }
// Mike
// Allen
// Jake
// 3
```

# Stack & Queue



# Hashtable