덱(deque)의 정의

  • 덱 또는 데큐(deque)는 양 방향에서 모두 데이터의 삽입과 삭제가 일어나는 자료구조이다.
  • 양 방향에서 데이터의 삽입 삭제가 발생하기 때문에 데큐는 양방향 연결 리스트로 구현하는 것이 효율이 좋다.

 

 

덱(deque)의 연산과 구현

  • 위에도 말했듯 덱은 양방향 연결 리스트로 구현하는 것이 효율적이다. 해당 자료구조는 이미 이전에 큐를 구현하며 같이 구현하였다.
  • 큐에서 데이터의 삽입이 tail에서 이루어졌고 삭제가 head에서 이루어졌다. 덱을 구현하기 위해서는 tail에서의 데이터 삭제와 head에서의 데이터 삽입을 추가적으로 구현하기만 하면 된다.
class Node{
    int data;
    Node prev;
    Node next;

    Node(int data){
        this.data = data;
        this.prev = null;
        this.next = null;
    }
}

class Deque{
    Node head;
    Node tail;
    int length;

    Deque(){
        head = new Node(-1);
        head.next = null;
        head.prev = null;

        tail = new Node(-1);
        tail.next = null;
        tail.prev = null;

        length = 0;
    }

    public void addFirst(int data){
       
    }

    public void addLast(int data){
        Node newNode = new Node(data);

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

        length++;
    }

    public int removeFirst(){
        int ret = -1;

        if (head.next == null || head.next == tail){
            return -1;
        }

        ret = head.next.data;
        head.next.next.prev = head;
        head.next = head.next.next;

        length--;

        return ret;
    }

    public int removeLast(){
        
    }

    public int peekFirst(){
        return head.next.data;
    }

    public int peekLast(){
        return tail.prev.data;
    }

    public int getLength(){
        return this.length;
    }

    public boolean isEmpty(){
        return this.length == 0;
    }

    public String toString(){
        StringBuilder sb = new StringBuilder();

        Node start = head.next;
        while(start.next != null){
            sb.append(start.data);
            sb.append(" ");
            start = start.next;
        }

        return sb.toString();
    }
}
  • 위 코드는 이전에 구현했던 큐에서 몇 가지 연산만 추가한 것이다.

 

 

덱(deque)의 head 삽입 연산

  • head에 삽입하는 것은 연결 리스트의 처음에 데이터를 삽입하는것과 동일하다.
  • 새로운 노드의 prev를 head로, next를 head.next로 설정하고, head.next의 prev와 head.next를 새로운 노드로 설정하면 끝난다.
  • 이전 큐에서  tail에 삽입하는 연산을 생각해 보면 tail이 head로 바뀐것과 그로 인해 prev와 next가 서로 바뀐것이 끝이다.
public void addFirst(int data){
    Node newNode = new Node(data);

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

    length++;
}
  • 덱이 비어있을경우, tail에도 설정하는 것이 필요하므로 그 부분을 따로 if를 통해 처리하였다.

 

 

덱(deque)의 tail 삭제 연산

  • tail 삭제 연산은 연결 리스트의 맨 마지막 요소를 삭제하는것과 동치이다.
  • 이 경우 tail.prev의 이전 노드 prev의 next를 tail을 가리키도록 하고, tail.prev를 tail.prev.prev로 바꾸어주면 손쉽게 해결된다.
  • 물론 덱이 비어있을 경우에 연산이 바로 끝나도록 처리해주어야 한다.
public int removeLast(){
    int ret = -1;

    if (tail.prev == null || tail.prev == head){
        return -1;
    }

    ret = tail.prev.data;
    tail.prev.prev.next = tail;
    tail.prev = tail.prev.prev;

    length--;

    return ret;
}

 

 

 

정리

  • 이렇게 연결 리스트의 구현에서부터 시작하여 이를 응용한 자료구조인 스택, 큐, 덱의 구현까지 끝마쳤다.
  • 해당 자료구조는 테스트에서 직접적으로 쓰이기보단 알고리즘의 구현에 자주 사용된다. 만약 테스트에 이러한 유형의 문제가 출제된다면 데이터의 삽입 삭제가 어떻게 돌아가는지에 대해 고민해보아야 할 것이다.
  • 덱의 전체적인 코드는 다음과 같다.
class Node{
    int data;
    Node prev;
    Node next;

    Node(int data){
        this.data = data;
        this.prev = null;
        this.next = null;
    }
}

class DoubleLinkedList{
    Node head;
    Node tail;
    int length;

    DoubleLinkedList(){
        head = new Node(-1);
        head.next = null;
        head.prev = null;

        tail = new Node(-1);
        tail.next = null;
        tail.prev = null;

        length = 0;
    }

    public void addFirst(int data){
        Node newNode = new Node(data);

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

        length++;
    }

    public void addLast(int data){
        Node newNode = new Node(data);

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

        length++;
    }

    public int removeFirst(){
        int ret = -1;

        if (head.next == null || head.next == tail){
            return -1;
        }

        ret = head.next.data;
        head.next.next.prev = head;
        head.next = head.next.next;

        length--;

        return ret;
    }

    public int removeLast(){
        int ret = -1;

        if (tail.prev == null || tail.prev == head){
            return -1;
        }

        ret = tail.prev.data;
        tail.prev.prev.next = tail;
        tail.prev = tail.prev.prev;

        length--;

        return ret;
    }

    public int peekFirst(){
        return head.next.data;
    }

    public int peekLast(){
        return tail.prev.data;
    }

    public int getLength(){
        return this.length;
    }

    public boolean isEmpty(){
        return this.length == 0;
    }

    public String toString(){
        StringBuilder sb = new StringBuilder();

        Node start = head.next;
        while(start.next != null){
            sb.append(start.data);
            sb.append(" ");
            start = start.next;
        }

        return sb.toString();
    }
}

'DataStructure > List' 카테고리의 다른 글

Stack의 활용 문제 - BOJ 25556번 포스택  (0) 2023.03.13
Stack의 활용 - VPS  (0) 2023.03.06
큐(Queue)의 정의와 구현  (0) 2023.02.23
Stack의 구현  (0) 2023.02.20
LinkedList의 구현 - Single Linked List  (0) 2023.02.20
복사했습니다!