---
# System prepended metadata

title: Singly linked list
tags: [Data Structure]

---

# Singly linked list
有以下特點

1. 新增、刪除元素的相較於陣列來說代價很小
2. 沒有index
3. 無法直接獲取特定的元素

singled linked list 是由一個Node一個個指向下一個，若要尋找某一特定元素，需要從頭部開始尋找。

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

例如我想要尋找到29這個數，會由**head開始確認，確認是否為29，不是進行下一個直到找到29這數字**。

insert的方式也非常簡單，例如我想在42與6之間insert數字77。

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

只需要將42的箭頭指向77並將77指向6即可

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

從頭或尾巴插入更簡單，從頭指向原本的頭即可，從尾直接指向新的數。

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

## 實作

Singly Linked List 是由一連串的Node串連而成，每個Node都會有自己的值，每個Node又會指向下一個Node。Singly Linked List也需要有append, unshift, insert, delete, get, set, pop方法。

### Node
首先先做出Node，該class應該需要有本身的值與next指向下一個Node

```javascript=
class Node {
  constructor(val) {
    this.val = val;
    this.next = null;
  }
}
```
### Singly Linked List
定義完Node後實作Singly Linked List，該class要有head, length, tail

```javascript=
class SinglyLinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }
}
```
### Append

1. 建立一個新的Node
2. 判斷若length是0，代表list中沒有Node的存在，新的Node等於head, tail
3. Length 加一
4. 回傳list

```javascript=
// 省略...
append(val) {
    const newNode = new Node(val);
    if (this.length === 0) {
      this.head = newNode;
      this.tail = this.head;
    } else {
      this.tail.next = newNode;
      this.tail = newNode;
    }

    this.length += 1;
    return this;
}
```

其中head與tail都reference Node，所以head與tail next每次執行都會update。

### Pop

1. 確認list的長度，若為0返回`undifine`
2. 從head至tail找到tail與tail的前一個
3. 設定新的tail
4. list長度減1
5. 確認tail長度，若為0將head與tail設為`null`
6. 回傳tail

```javascript=
// 省略...
pop() {
    if (this.length === 0) return undefined;

    let current = this.head;
    let prev = this.head;

    while (current) {
      if (current.next === null) {
        this.tail = prev;
        this.tail.next = null;
        this.length -= 1;

        if (this.length === 0) {
          this.tail = null;
          this.head = null;
        }

        return current;
      }
      prev = current;
      current = current.next;
    }
  }
}
```
### Shift

1. 確認長度是否為0，是的話回傳`undefined`
2. 保存this.head
3. this.head.next 為新的head
4. length減一
5. 若length為0，設tail為null
6. 回傳保存下來的this.head

```javascript=
// ...省略
shift() {
    if (this.length === 0) return undefined;

    const head = this.head.val;
    this.head = this.head.next;
    this.length -= 1;

    if (this.length === 0) this.tail = null;
    return head;
}
```

### Unshift

1. 傳入參數值，建立新的Node
2. 判斷head是否存在，若不存在this.head = 新的Node
3. 若存在則new Node的next是現在的head
4. this.head替換成new Node
5. 長度加一
6. 回傳list

```javascript=
// ...省略
unshift(val) {
    const newNode = new Node(val);

    if (!this.head) {
      this.head = newNode;
      this.tail = this.head;
    } else {
      newNode.next = this.head;
      this.head = newNode;
    }

    this.length += 1;
    return this;
}
```
### Get

1. 傳入Index(從0開始)至method
2. 如果index < 長度 + 1或小於0 回傳`undefined`
3. 建立current儲存this.head
4. 若index為0則回傳current
5. 否則current = current.next
6. index - 1
7. 重複第4步驟

```javascript=
// ...省略
get(index) {
    if (this.length < index + 1 || index < 0) return undefined;
    let current = this.head;

    while (index) {
      current = current.next;
      index -= 1;
    }
    return current;
}
```
**O(n)**
### Set

1. 傳入index與value
2. 從Get method 得到node
3. 若得到的node不存在，回傳`false`
4. 修改node value並回傳`true`

```javascript=
// ...省略
set(index, val) {
    const node = this.get(index);

    if (!node) return false;

    node.val = val;
    return true;
}
```

### Insert

1. 傳入index與value
2. 確認index長度若 < 0或大於list的長度return `false`
3. 若index = list的長度 call append method, return `true`
4. 若index = 0 call unshift method, return `true`
5. 用get method 找尋index前一個node(preNode)
6. 實作新的node(newNode)
7. newNode的next = newNode的next
8. preNode的next = newNode
9. 長度加一,回傳`true`

```javascript=
// ...
insert(index, val) {
    if (index < 0 || this.length < index) return false;
    if (index === this.length) return !!this.append(val);
    if (index === 0) return !!this.unshift(val);

    const preNode = this.get(index - 1);
    const newNode = new Node(val);

    newNode.next = preNode.next;
    preNode.next = newNode;
    this.length += 1;
    return true;
}
```

**O(1)**
### Remove

1. 傳入index
2. 若index < 0 或 index > list長度減一 return `undefined`
3. 若index = list長度減一 return and call pop method
4. index = 0 return and call shift method
5. call get method 得到list前一個node(preNode)
6. preNode的next是要被移除的Node(removedNode)
7. preNode的next = removedNode的next
8. 長度減一
9. 回傳removedNode

```javascript=
remove(index) {
    if (index < 0 || this.length - 1 < index) return undefined;
    if (index === this.length - 1) return this.pop();
    if (index === 0) return this.shift();

    const preNode = this.get(index - 1);
    const removedNode = preNode.next;
    preNode.next = removedNode.next;
    this.length -= 1;
    return removedNode;
}
```
**O(1)** or **O(n)**

### Reverse

1. 交換head與tail, 並儲存原head的list(node)
2. 定義next與pre = null
3. loop next = node.next, node.next = pre, pre = node, node = next
4. 回傳this

![](https://i.imgur.com/wu8QqKf.jpg)

```javascript=
reverse() {
    let node = this.head;
    this.head = this.tail;
    this.tail = node;

    let next;
    let pre = null;

    for (let i = 0; i < this.length; i += 1) {
      next = node.next;
      node.next = pre;
      pre = node;
      node = next;
    }

    return this;
}
```
###### tags: `Data Structure`
