0

[DSA] Linked list

Giới thiệu

Là một kiểu dữ liệu gồm đầu (head), đuôi (tail) và độ dài (length)

Linked list gồm nhiều node, 1 node có 1 giá trị và 1 con trỏ trỏ tới node khác hoặc null

Có 2 loại linked list:

  • Singly linked list (danh sách liên kết đơn)
  • Doubly linked list (danh sách liên kết đôi)

Singly Linked lists (danh sách liên kết đơn)

image.png

Khởi tạo

Tạo 1 class cho node của Singly linked list

class NodeSinglyLinkedList {
  val: string;
  next: NodeSinglyLinkedList | null;

  constructor(val: string) {
    this.val = val;
    this.next = null;
  }
}

Tạo 1 class chứa các method của Singly Linked list

class SinglyLinkedList {
  head: NodeSinglyLinkedList | null;
  tail: NodeSinglyLinkedList | null;
  length: number;

  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }
  
  push(val){}
  
  pop(){}
  
  unshift(val){}
  
  shift(){}
  
  get(val){}
  
  insert(val, position){}
  
	remove(position){} 
}

Khởi tạo các method

push

  push(val) {
    const newNode = new NodeSinglyLinkedList(val);

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

    this.length++;
    return this;
  }

pop

  pop() {
    if (!this.head) {
      return undefined;
    }

    let current = this.head;
    let newTail = current;

    while (current.next) {
      newTail = current;
      current = current.next;
    }

    this.tail = newTail;
    this.tail.next = null;

    this.length--;
    return this;
  }

unshift

  unshift(val) {
    const newNode = new NodeSinglyLinkedList(val);

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

    this.length++;
    return this;
  }

shift

  shift() {
    if (!this.head) {
      return undefined;
    } else {
      const currentHead = this.head;
      this.head = currentHead.next;
    }

    this.length--;
    return this;
  }

get

  get(position) {
    if (position < 0 || position > this.length) return null;

    let counter = 0;
    let head = this.head;
    while (counter < this.length) {
      if (counter === position) {
        return head;
      }
      head = head.next;
      counter++;
    }
  }

insert

  insert(val, position) {
    if (position < 0 || position > this.length) return null;

    const newNode = new NodeSinglyLinkedList(val);

    if (position === 0) {
      return this.unshift(val);
    }

    if (position === this.length) {
      return this.push(val);
    }

    const prevNode = this.get(position - 1);
    const prevNodeNext = prevNode.next;
    prevNode.next = newNode;
    newNode.next = prevNodeNext;
  }

remove

  remove(position) {
    if (position < 0 || position > this?.length) return null;

    if (position === 0) {
      return this.shift();
    }

    if (position === this.length - 1) {
      return this.pop();
    }

    const currentNode = this.get(position);
    const prevNode = this.get(position - 1);
    prevNode.next = currentNode.next;

    return this;
  }

Doubly Linked lists (danh sách liên kết đôi)

image.png

Khởi tạo

Tạo 1 class cho node của Singly linked list

class NodeDoublyLinkedList {
  val: string;
  next: NodeDoublyLinkedList | null;
  prev: NodeDoublyLinkedList | null;

  constructor(val: string) {
    this.val = val;
    this.next = null;
    this.prev = null;
  }
}

Tạo 1 class chứa các method của Singly Linked list

class DoublyLinkedList {
  head: NodeDoublyLinkedList | null;
  tail: NodeDoublyLinkedList | null;
  length: number;

  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }
  
  push(val){}
  
  pop(){}
  
  unshift(val){}
  
  shift(){}
  
  get(val){}
  
  insert(val, position){}
  
	remove(position){} 
}

Khởi tạo các method

push

  push(val) {
    const newNode = new NodeDoublyLinkedList(val);

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      newNode.prev = this.tail;
      this.tail = newNode;
    }
    this.length++;
    return this;
  }

pop

  pop() {
    if (!this.head) {
      return undefined;
    }

    const newTail = this.tail.prev;
    this.tail.next = null;
    this.tail = newTail;
    this.length--;

    return this;
  }

unshift

  unshift(val) {
    const newNode = new NodeDoublyLinkedList(val);

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

    this.length++;
    return this;
  }

shift

  shift() {
    if (!this.head) {
      return undefined;
    } else {
      const currentHead = this.head;
      this.head = currentHead.next;
      this.head.prev = null;
    }

    this.length--;
    return this;
  }

get

  get(position) {
    if (position < 0 || position > this.length) return null;

    let counter = 0;
    let head = this.head;
    while (counter < this.length) {
      if (counter === position) {
        return head;
      }
      head = head.next;
      counter++;
    }
  }

insert

  insert(val, position) {
    if (position < 0 || position > this.length) return null;

    const newNode = new NodeDoublyLinkedList(val);

    if (position === 0) {
      return this.unshift(val);
    }

    if (position === this.length) {
      return this.push(val);
    }

    const currentNode = this.get(position);
    const prevNode = this.get(position - 1);
    prevNode.next = newNode;
    newNode.prev = prevNode;
    newNode.next = currentNode;
    currentNode.prev = newNode;

    this.length++;
    return this;
  }

remove

  remove(position) {
    if (position < 0 || position > this?.length) return null;

    if (position === 0) {
      return this.shift();
    }

    if (position === this.length - 1) {
      return this.pop();
    }

    const prevNode = this.get(position - 1);
    const nextNode = this.get(position + 1);
    prevNode.next = nextNode;
    nextNode.prev = prevNode;

    this.length--;

    return this;
  }

Kết luận

Từ việc triền khai các method ở trên ta có được bảng so sánh độ phức tạp của 2 loại linked list như sau:

Method Singly Doubly
push O(1) O(1)
pop O(n) O(1)
unshift O(1) O(1)
shift O(1) O(1)
get O(n) O(n)
insert O(n) O(n)
remove O(n) O(n)

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí