본문 바로가기
컴퓨터 사이언스(CS)/자료구조

[CS/자료구조] 불변 연결 리스트 (Immutable LinkedList)

by char_lie 2024. 7. 24.
반응형
연결 리스트(LinkedList)

출처 : https://kr.pinterest.com/pin/635922409897499713/

📝연결 리스트란?

  • 순차적으로 연결된 공간에 데이터를 나열하는 데이터 구조
  • 떨어진 곳에 존재하는 데이터를 화살표로 연결해서 관리하는 데이터 구조
  • 각 요소가 데이터와 다음 요소를 참조하는 정보를 포함하는 노드로 구성된 형태

연결 리스트의 요소

  • 노드(Node) : 연결 리스트의 기본 단위로, 데이터와 다음 노드를 가리키는 필드로 구성
  • 포인터(pointer) : 각 노드 안에서 다음이나 이전의 노드와의 연결 정보를 갖고 있는 공간
  • 헤드(Head) : 연결 리스트의에서 가장 처음 위치하는 노드. 리스트 전체를 참조하는데 사용
  • 테일(Tail) : 연결 리스트의 가장 마지막에 위치하는 노드. 다음 노드가 존재하지 않으므로 링크된 노드의 필드 값은 Null이다.

연결 리스트 구현(JavaScript)

class Node {
    constructor(data, next = null) {
        this.data = data;
        this.next = next;
    }
}

class LinkedList {
    constructor() {
        this.head = null;
    }

    append(data) {
        const newNode = new Node(data);
        if (this.head === null) {
            this.head = newNode;
        } else {
            let current = this.head;
            while (current.next !== null) {
                current = current.next;
            }
            current.next = newNode;
        }
    }

    prepend(data) {
        const newNode = new Node(data, this.head);
        this.head = newNode;
    }

    remove(data) {
        if (this.head === null) {
            return;
        }

        if (this.head.data === data) {
            this.head = this.head.next;
            return;
        }

        let current = this.head;
        while (current.next !== null) {
            if (current.next.data === data) {
                current.next = current.next.next;
                return;
            }
            current = current.next;
        }
    }

    find(data) {
        let current = this.head;
        while (current !== null) {
            if (current.data === data) {
                return current;
            }
            current = current.next;
        }
        return null;
    }
}
  • 위 코드 구조는 값을 추가하거나, 삭제, 찾는 등의 기능을 수행할 수 있음.
  • 단순 연결리스트이므로 "직접적으로" 값을 참조하여 삭제, 추가 기능을 수행할 수 있음.
반응형
불변성(Immutability)

📝불변성이란?

  • 데이터 구조나 객체가 생성 이후로 변경되지 않는 것을 의미함.
  • 초기 상태에서 값을 변경할 수 없기 때문에 상태 변화가 없음.
  • 주로 리액트와 같은 상태(state)를 관리할 때 유리함
  • 데 이터가 변경되지 않고 변경 시 복사본을 만들어 수정
  • 함수형 프로그래밍에서 중요한 핵심 개념 중 하나.
❓ 함수형 프로그래밍
  • 수학적 함수 개념을 바탕으로 하는 프로그래밍 패러다임
  • 가독성과 테스트에 매우 용이해지고, 부수적인 효과가 없으므로 병렬처리에 용이함
  • 상태변화가 일어나지 않으므로 버그 추적 및 유지보수에 용이

순수 함수(pure Function)

function add(a, b) {
    return a + b; 
}
  • 동일한 입력에 대해 항상 동일한 출력을 반환하고 외부 상태를 변경하지 않는 함수
  • 테스트, 디버깅에 용이함

클로저 (Closure)

function createCounter() {
    let count = 0;
    return function() {
        count++;
        return count;
    };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
  • 함수 내부의 변수를 외부에서 접근할 수 없는 객체
  • 동적으로 함수 생성이 가능하며, 생성된 함수가 외부 변수를 기억함

고차 함수(Higher-Order Function) 

function map(array, fn) {
    return array.map(fn);
}

const doubled = map([1, 2, 3], x => x * 2);
console.log(doubled);
  • map, filter, reduce 등의 함수
  • 재사용성을 높히고, 추상화하여 코드의 가독성을 높일 수 있음
  • 다만, 복잡성이 증가하여 함수의 흐름 추적이 어려울 수 있음

불변성을 사용하는 이유

  • 데이터 흐름을 쫒아가기 용이함(유지보수에 유리함)
  • 불변성을 지키면서 데이터를 변화시키면 예상 가능하고 신뢰할 수 있는 코드가 될 수 있음
  • 불변성이 가장 많이 적용된 라이브러리가 바로 리액트(state, props 관리)

가변 데이터를 불변 타입으로 구현하기 위한 요소

const person = { name: 'Alice', age: 25 };
const updatedPerson = { ...person, age: 26 };
  • 객체나 데이터 구조가 생성된 후 변경되지 않고, 필요 시 새로운 객체 생성하여 변화
  • 수정시에도 새로운 객체를 생성하여 데이터 이전 상태 보존
  • 객체의 일부만 변경할 때, 나머지 부분은 부분 복사하여 재사용 후 새로운 객체 생성

🤔 그렇다면 불변성과 연결 리스트를 합치게 된다면?

👍 장점
  • 상태가 변하지 않으므로 코드의 동작 예측이 쉬워지고 디버깅이 용이함
  • 상태가 변하지 않으므로 여러 스레드에서 동시 접근해도 안전함
  • 재사용성을 고려하므로 복사 및 수정이 용이해짐
  • 데이터 흐름이 명확해짐
👎 단점
  • 새로운 객체를 생성하므로 메모리 사용량이 증가
  • 메모리 사용량이 증가하면서 오버헤드 발생 가능 (최신 JavaScript 엔진은 효율적 메모리를 처리하므로 많은 상황에선 문제 발생하지 않음)

불변 연결 리스트 구현(JavaScript)

class Node {
    constructor(data, next = null) {
        this.data = data;
        this.next = next;
    }
}

class ImmutableLinkedList {
    constructor(head = null) {
        this.head = head;
    }

    append(data) {
        const newNode = new Node(data);
        if (this.head === null) {
            return new ImmutableLinkedList(newNode);
        } else {
            let current = this.head;
            let previous = null;
            while (current !== null) {
                previous = current;
                current = current.next;
            }
            previous.next = newNode;
            return new ImmutableLinkedList(this.head);
        }
    }

    prepend(data) {
        const newNode = new Node(data, this.head);
        return new ImmutableLinkedList(newNode);
    }

    remove(data) {
        if (this.head === null) {
            return this;
        }

        if (this.head.data === data) {
            return new ImmutableLinkedList(this.head.next);
        }

        let current = this.head;
        while (current.next !== null) {
            if (current.next.data === data) {
                current.next = current.next.next;
                return new ImmutableLinkedList(this.head);
            }
            current = current.next;
        }
        return this; 
    }

}
  • 기존 연결리스트와 다르게 값을 추가 및 제거시 새로운 객체를 반환하는 형태
반응형

댓글