Skip to content

Latest commit

 

History

History
116 lines (82 loc) · 9.19 KB

Data Structure.md

File metadata and controls

116 lines (82 loc) · 9.19 KB

Data Structure

  • 자료구조는 "데이터를 조직하는 방법"이라고 할 수 있다. 또는 "데이터를 표현하고 관리하고 처리하기 위한 구조"를 의미한다.

📖 Contents


Stack과 Queue의 차이

  • Stack이란, 데이터를 차곡차곡 쌓아올린 형태의 자료구조이다. 데이터가 순서대로 쌓이다가 가장 마지막에 삽입된 자료가 가장 먼저 삭제되는 구조를 가지고 있다.

    • Stack은 정해진 방향으로만 쌓을 수 있고, top으로 정한 곳을 통해서만 접근할 수 있다. 새로 삽입되는 자료는 top이 가리키는 가장 맨 위에 쌓이게 되고 자료를 삭제할 때도 top을 통해서 삭제가 가능.
    • Stack에서 삽입 연산은 push / 삭제 연산은 pop이라고 한다. 후입선출의 구조로 LIFO(Last In First Out)이라고 부른다.
    • ex) 웹 브라우저 방문 기록 뒤로가기, 실행 취소(undo), 역순 문자열 만들기, 후위 표기법 계산
  • 큐(Queue)는 먼저 들어온 것이 먼저 나가는 선입선출로 FIFO(First In First Out)의 구조를 가지고 있다.

    • FIFO 구조를 위해서 큐의 왼쪽 끝에는 삽입 작업이 / 오른쪽 끝에는 삭제 작업이 나뉘어서 이루어진다.
    • 삽입 연산이 이루어지는 곳을 리어(rear)라고 하고, 리어에서 이루어지는 삽입 연산을 인큐(Enqueue)라고 부른다.
    • 삭제 연산이 이루어지는 곳을 프론트(front)라고 하고, 프론트에서 이루어지는 삭제 연산을 디큐(Dequeue)라고 부른다.
    • ex) 은행 업무, 대기열 순서와 같은 우선순위의 작업 예약 등, 서비스 센터 대기시간, 프로세스 관리

시간복잡도란

  • 시간 복잡도란, 우리가 작성한 코드의 실행시간이 실행해보기 전에 정확하게 추측하는 것은 힘들겠지만 반복문을 몇 번 사용했는지, 입력값은 어떻게 되는지 등을 통해 대략적으로 추측할 수 있다. 즉, 입력값과 연산 수행 시간의 상관관계를 나타내는 척도를 시간 복잡도라고 한다.

  • 시간복잡도 예시

    • 복잡한 곱하기와 같은 연산이 없고 넣으면 바로 결과값이 나오는 O(1)
    • for 루프 하나는 O(n)
    • for문안에 for문은 O(n^2)
    • O(n^2+n) 예시
for i in range(1000000):
    for i in range(10000):
        pass
        
for i in range(100):
    ...
  • 시간복잡도를 고려한다면, for문과 while문은 최대한 사용하지 않는 것이 좋다.

자료구조 heap

  • 힙(heap)은 무언가를 차곡차곡 쌓아 올린 더미라는 뜻으로, 완전이진트리의 형태로 만들어진 자료구조이다. 즉, 위로 갈수록 노드의 수가 줄어드는 모습이다. 힙은 최댓값 혹은 최솟값을 빠르게 찾아내기에 유리한 자료구조이다.

    • 이진트리는 각 노드가 최대 2개의 자식을 갖는 트리를 뜻한다. 즉, 각 노드는 자식이 없거나 한개이거나 두개만을 갖게 된다.
    • 그리고 완전이진트리는 마지막 레벨을 제외하고 모든 레벨이 완전히 채워져 있는 트리 자료구조이다. 또한, 마지막 레벨은 꽉 차 있지 않아도 되지만, 노드가 왼쪽에서 오른쪽으로 채워져야 한다.
  • 힙을 만드는 과정

    • 값 삽입 - 힙 구조로 변경 - 값 삽입 - 힙 구조로 변경
    • 이 과정에서 힙은 항상 부모 노드가 자식 노드보다 커야 한다는 조건이 지켜져야 한다. 그래서 매번 값이 들어올 때마다 값을 비교하고 swap을 해줘야 한다. 자식 노드들 끼리는 값을 비교하지 않는다.
    • 힙 구조가 완성되면 완전 이진트리이면서 부모 노드가 자식 노드보다 큰 트리 구조이다. 이러한 과정을 통해 최댓값을 빠르게 찾을 수 있는 구조가 바로 힙이다.
    • 힙 구조는 최댓값 혹은 최솟값을 빨리 찾기 위한 구조이지 이걸 사용했다고 정렬이 되지는 않는다.
  • 관련 블로그


링크드 리스트란

  • 링크드 리스트란, 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식으로 데이터를 저장하는 자료 구조이다. 데이터를 담고 있는 노드들이 연결되어 있는데, 노드의 포인터가 다음이나 이전의 노드와의 연결을 담당하게 된다.
    • 링크드 리스트를 python으로 구현하면, 링크드리스트에서 가장 시작점인 데이터를 의미하는 Head부터 탐색해서 뒤에 노드가 추가된다. 그리고 링크드리스트에서 가장 마지막 데이터를 의미하는 Tail까지 존재한다.
    • 하나의 노드를 클래스로 구현하면 self.data = data로 데이터가 있고, self.next = None라는 코드로 다음 데이터를 연결하기 위해 작성한다. Next=None(또는 Null)은 다음 데이터가 없을 경우 포인터의 주소값을 None(또는 Null)이라고 한다.

어레이 리스트와 링크드 리스트의 차이

image

  • 위의 내용과 같이, ArrayList는 index가 있고, LinkedList는 각 원소마다 앞,뒤 원소의 위치값을 가지고 있다. 이러한 특징으로 조회, 삽입, 삭제 시 아래와 같은 시간복잡도 차이를 가진다.

image

  • ArrayList

  • get/set

    • 배열의 index를 통해 접근하는 방식이기 때문에, random access속도가 빠르며 get/set 메소드는 상수 시간을 가지게 된다.
  • add

    • ArrayList는 배열이기 때문에 중간에 값을 끼워넣는 연산이 불가능하다.
    • 만약 새로운 값을 추가하려고 할 때, List의 크기가 생성되어 있는 배열의 size(생성시 따로 설정하지 않았다면 size = 10인 배열이 생성된다)보다 커지게 되면, 이전 크기의 2배가 되는 배열을 생성해 배열 전체를 복사하여 새로운 배열에 복사하고 제일 뒤에 값을 추가해야 한다.
    • 따라서 기존에 있던 배열에서 추가하고 싶은 index부터 마지막 index까지 한 칸씩 뒤로 미루는 연산이 필요하다. 그래서 해당하는 인덱스를 찾아가는 시간(O(1)) + 배열을 복사하는 시간(O(n)) = O(n)의 시간이 소요된다.
  • remove

    • add와 유사하게 remove는 삭제된 index + 1부터 마지막 index까지 한 칸씩 앞으로 당기는 연산을 하게 된다. 따라서, add와 동일한 O(n)의 시간 복잡도를 가지게 된다.

  • LinkedList

  • get/set

    • LinkedList는 연결 리스트 형태를 띄고 있기 때문에 해당하는 index에 대한 값을 얻어올 때 시작이나 끝에서부터 해당 index까지 순차적으로 접근하며 값을 얻어온다. 따라서, 시간 복잡도는 O(n)을 가진다.
  • add

    • 일반적인 경우 : 추가를 원하는 index에 도달할 때까지 순차 접근을 하는 시간복잡도 O(n) / index-1의 노드의 next와 index+1의 prev를 새로 추가한 노드에 연결하는 작업은 n에 영향을 받지않는 상수 시간이기 때문에 O(1)이다. 따라서, O(n)의 시간복잡도를 가진다.
    • 시작이나 끝에 요소를 추가할 때 : LinkedList는 head와 tail을 갖는 doubleLinkedList의 구조이기 때문에 시작과 끝에 해당하는 노드을 찾아가는데는 O(1)이라는 시간 복잡도를 갖게된다. 따라서, 시간 복잡도는 O(1)이다.
  • remove

    • 일반적인 경우 : 원하는 index에 도달할 때까지 순차 접근을 하는 시간복잡도 O(n) / index - 1의 노드의 next를 index의 next의 요소와 연결하고, index + 1의 prev를 index의 prev요소로 변경하면 된다. List의 길이에 영향을 받지않는 상수 시간이기 때문에 O(1)이다. 따라서, O(n)의 시간복잡도를 가진다.
    • 시작이나 끝에 요소를 삭제할 때 : 시작과 끝 요소를 찾아가는데 O(1)이라는 시간 복잡도를 갖기 때문에, 시간 복잡도는 O(1)이다.

  • 2가지 자료구조 비교하기

    • 일반적으로 get/set을 자주 사용한다면? ArrayList
    • 처음이나 끝에 잦은 삽입, 삭제가 발생한다면? LinkedList
    • 하지만, 공간 복잡도의 경우 ArrayList는 연속된 메모리안에 저장되므로 낭비되는 공간이 없기 때문에 종종 속도가 더 빠른 경우가 발생하기도 한다. LinkedList는 요소마다 두개의 참조 노드가 필요하기 때문에 더 많은 공간을 차지하고, 메모리 여기저기 노드가 흩어져 존재하는 경우 효율이 더욱 떨어질 수 있으니 잘 선택해야한다.
  • 참고 블로그, 참고 블로그2