[자료 구조와 알고리즘] 연결리스트(Linked list)

2023. 5. 17. 21:23·📗 self-study/📗 inflearn

 

 

 

🔥 그림으로 쉽게 배우는 자료 구조와 알고리즘

 

연결 리스트(Linked List)

 

 

 

 

📍 연결 리스트(Linked List)

👉🏻 저장하려는 데이터들을 분산해 할당하고 데이터들을 노드로 서로 연결해 줌

👉🏻 첫 노드의 주소를 알고 있으면, 연결되는 다음 데이터도 모두 알 수 있음

👉🏻 노드: 데이터를 담는 변수 하나와 다음 데이터를 가리키는 변수 1개를 가지고 있음

 

 

 

📍 장점

👉🏻 빈 메모리 공간 아무 곳에나 생성 후 연결만 해 주면 되기 때문에 초기 크기를 알지 않아도 됨

👉🏻 중간에 데이터를 삽입할 때도 다음 노드의 연결만 바꾸어 주면 되기 때문에 간편함 (삭제도 마찬가지)

 

 

 

📍 단점

👉🏻 데이터가 모두 떨어져 있어 바로 접근 불가능(4번째 노드에 접근하고 싶다면 첫 번째 노드를 기준으로 다음 데이터로 하나씩 넘어가야 함)

👉🏻 데이터 참조 O(n)의 성능을 가짐

 

 

 

📍 배열과 연결 리스트

👉🏻 배열의 크기는 고정 / 연결 리스트의 크기는 동적

👉🏻 배열의 주소는 연속 할당 / 연결 리스트의 주소는 불연속(런타임)

 

👉🏻 배열의 데이터 참조 성능 O(1) / 연결 리스트의 데이터 참조 성능 O(n) 

 

👉🏻 배열의 삽입과 삭제 성능 O(n) / 연결 리스트의 삽입과 삭제 성능 O(n)

 

✔️ 참조를 자주 한다면 배열 사용, 삽입과 삭제가 자주 일어난다면 연결 리스트를 사용하는 것이 메모리 절약에 효율적!

 

 

 

 

🔥 그림으로 쉽게 배우는 자료 구조와 알고리즘

 

연결 리스트 구현

 

 

 

 

📍 추상 자료형(Abstract Data Type)

👉🏻 어떤 데이터와 그 데이터에 대한 연산 기능을 표기하는 것

👉🏻 연결 리스트의 추상 자료형

 

[ 테스트 코드 작성 ]

[ LinkedList.mjs ]

class Node{
    // 클래스를 인스턴스화 했을 때 자동으로 호출되는 생성자 만들기
    constructor(data, next = null){
        // 생성자로 초기화
        // next 기본값: null
        // data는 필수지만 next는 입력하지 않을 경우 null 들어옴
        // 클래스 내의 변수: 프로퍼티
        this.data = data;
        this.next = next;
    }
}

// 다른 자바 스크립트 파일에서 node 클래스를 참조할 수 있게 export 줌
export { Node };
[ test.mjs ]

// from 뒤에는 node 클래스가 저장된 파일의 경로를 적어 줌 
import { Node } from './LinkedList.mjs';
// test.mjs에서 node 클래스를 사용할 수 있게 됨

// 테스트 코드 작성
let node1 = new Node(1);
let node2 = new Node(2);
let node3 = new Node(3);

// 연결 과정
node1.next = node2;
node2.next = node3;

console.log(node1.data);
console.log(node1.next.data);
console.log(node1.next.next.data);

 

[ 연결 리스트 클래스 만들기 ]

[ LinkedList.mjs ]

class LinkedList {
    constructor(){
        // 매개변수 필요 없음
        this.head = null;
        this.count = 0; // 총 노드 개수
    }

    // 함수의 원형
    insertAt(index, data) {
        if(index > this.count || index < 0) {
            throw new Error("범위를 넘어갔습니다.");
        }

        // 삽입할 노드 생성
        let newNode = new Node(data);

        if(index == 0) { // 새로 삽입하는 노드가 head임
            newNode.next = this.head;
            this.head = newNode;
        } else { // 새로 삽입하는 노드가 head 아님
            // 원하는 인덱스까지 노드 타고 들어가 새로 삽입
            let currentNode = this.head;

            // 목표 인덱스의 바로 전까지 접근
            for(let i = 0; i < index - 1; i++) {
                currentNode = currentNode.next;
            }
            newNode.next = currentNode.next;
            currentNode.next = newNode;
        }
        this.count++;
    }
}
export { Node, LinkedList };

 

   1. 연결 리스트의 모든 데이터 출력 👉🏻  printAll()

    printAll() {
        let currentNode = this.head;
        let text = "[";
        
        while(currentNode != null) {
            text += currentNode.data;
            currentNode = currentNode.next;

            if(currentNode != null) {
                text += ", ";
            }
        }

        text += "]";
        console.log(text);
    }
[ test.mjs ]

list.printAll();
// 출력

   2. 연결 리스트의 모든 데이터 제거 👉🏻 clear()

[ LinkedList.mjs ]

    // 리스트 모든 함수 제거
    clear() {
        this.head = null;
        this.count = 0;
    }
[ test.mjs ]

console.log("===== clear() 호출 =====");
list.clear(0);
list.printAll();

 

   3. 인덱스 삽입 👉🏻 insertAt(index, data);

[ LinkedList.mjs ]

    // 함수의 원형
    insertAt(index, data) {
        if(index > this.count || index < 0) {
            throw new Error("범위를 넘어갔습니다.");
        }

        // 삽입할 노드 생성
        let newNode = new Node(data);

        if(index == 0) { // 새로 삽입하는 노드가 head임
            newNode.next = this.head;
            this.head = newNode;
        } else { // 새로 삽입하는 노드가 head 아님
            // 원하는 인덱스까지 노드 타고 들어가 새로 삽입
            let currentNode = this.head;

            // 목표 인덱스의 바로 전까지 접근
            for(let i = 0; i < index - 1; i++) {
                currentNode = currentNode.next;
            }
            // 새로운 노드가 currentNode의 next를 가리킴
            newNode.next = currentNode.next;
            // currentNode가 새로운 노드를 가리킴
            currentNode.next = newNode;
        }
        this.count++;
    }
[ test.mjs ]

console.log("===== insertAt() 다섯 번 호출 =====");
list.insertAt(0, 0);
list.insertAt(1, 1);
list.insertAt(2, 2);
list.insertAt(3, 3);
list.insertAt(4, 4);
// 삽입 완료

 

   4. 마지막 데이터 뒤에 삽입 - 3번으로도 가능하나 조금 더 효율적으로 진행하기 위함 👉🏻 insertLast(data);

[ LinkedList.mjs ]

    // 마지막 데이터 뒤에 삽입
    insertLast(data){
        this.insertAt(this.count, data);
    }

 

[ test.mjs ]

console.log("===== insertLast() 세 번 호출 =====");
list.insertLast(0);
list.insertLast(1);
list.insertLast(2);
list.printAll();

 

 5. 인덱스 삭제 👉🏻 deleteAt(index);

[ LinkedList.mjs ]
    // deleteAt 함수 원형
    deleteAt(index) {
        if(index >= this.count || index < 0) {
            throw new Error("제거할 수 없습니다.");
        }
		// 노드 순회 변수
        let currentNode = this.head;
        if(index == 0){ // 첫 번째 노드(head 노드) 제거
            let deleteNode = this.head;
            this.head = this.head.next;
            this.count--;
            return deleteNode;
        } else { // 첫 번째 노드(head 노드)가 아닌 노드 제거
            for(let i = 0; i < index - 1; i++){
                currentNode = currentNode.next;
            }
            // 현재 currentNode는 제거할 노드의 이전 노드를 가리킴
            
            let deleteNode = currentNode.next;
            // 제거할 노드의 next 노드를 가리키게 함
            currentNode.next = currentNode.next.next;
            this.count--;
            return deleteNode;
        }
    }

 

[ test.mjs ]

console.log("===== delteAt() 호출 =====");
list.deleteAt(0);
list.printAll();
list.deleteAt(1);
list.printAll();

 

 

 6. 마지막 데이터 삭제 👉🏻 deleteLast();

[ LinkedList.mjs ]

    deleteLast() {
        return this.deleteAt(this.count - 1);
    }

 

[ test.mjs ]

console.log("===== delteLast() 호출 =====");
// 현재 리스트에는 데이터 1개밖에 없으므로 하나 더 삽입
list.insertLast(5);
list.deleteLast();
list.deleteLast();
// 데이터 두 개인데 세 번 호출해서 "제거할 수 없습니다" 오류 남
// list.deleteLast();
list.printAll();

 

   7. 원하는 인덱스의 데이터 읽기 👉🏻 getNodeAt(index);

[ LinkedList.mjs ]

    getNodeAt(index) {
        if(index >= this.count || index < 0) {
            throw new Error("범위를 넘어갔습니다.");
        }

        // 리스트 순회 변수 만들어 헤드와 같은 노드 가리킴
        let currentNode = this.head;
        for(let i = 0; i < index; i++) {
            currentNode = currentNode.next;
        }
        return currentNode;
    }
[ test.mjs ]

console.log("===== getNodeAt() 호출 =====");
list.insertLast(1);
list.insertLast(2);
list.insertLast(3);
list.insertLast(4);
list.insertLast(5);

let secondNode = list.getNodeAt(2);
console.log(secondNode);

 

저작자표시 비영리 변경금지 (새창열림)
'📗 self-study/📗 inflearn' 카테고리의 다른 글
  • [자료 구조와 알고리즘] 덱(Deque)
  • [자료 구조와 알고리즘] 스택(Stack)과 큐(Queue)
  • [자료 구조와 알고리즘] 자바스크립트 실행 환경 구축과 배열
  • [자료 구조와 알고리즘] 시간 복잡도
천재강쥐
천재강쥐
  • 천재강쥐
    디버거도 버거다
    천재강쥐
  • 전체
    오늘
    어제
    • Category (467)
      • 진짜 너무 궁금한데 이걸 나만 몰라...? (0)
      • 💾 Portfolio (2)
      • 🐤 CodingTest (28)
        • Java (20)
        • ᕕ(ꐦ°᷄д°᷅)ᕗ❌ (5)
      • 🚀 from error to study (142)
        • AI (1)
        • Cloud (2)
        • DB (12)
        • Front-End (16)
        • Github (14)
        • Java (39)
        • Mac (7)
        • Normal (29)
        • Server (22)
      • 📘 certificate (44)
        • 📘 리눅스마스터1급 (1)
        • 📘⭕️ 정보처리기사 (40)
        • 📘⭕️ SQLD (3)
      • 📗 self-study (234)
        • 📗 inflearn (35)
        • 📗 생활코딩 (8)
        • 📗 KH정보교육원 당산지원 (190)
      • 🎨 Scoop the others (0)
        • 📖 Peeking into other people.. (0)
        • 🇫🇷 (0)
        • 📘⭕️ 한국사능력검정시험 심화 (11)
        • 오블완 (4)
  • 인기 글

  • hELLO· Designed By정상우.v4.10.1
천재강쥐
[자료 구조와 알고리즘] 연결리스트(Linked list)
상단으로

티스토리툴바