DevGang

데이터 구조 본문

Study/정리

데이터 구조

별천랑 2021. 4. 7. 23:48

배열(Array)

  • 배열은 많은 수의 항목을 메모리에 저장할 때 사용할 수 있는 방법 가운데 가장 단순하고 기본적인 방법이다.
  • 배열은 메모리에 연속적인 공간을 할당하여 만든다.
  • 배열 속에 저장하려는 항목은 그 메모리 공간 속에 순차적으로 기록한다.
  • 장점 - 프로그래밍하기 쉽고 접근시간이 상수 시간이다.
  • 단점 - 연속적으로 이어진 메모리 공간에만 저장할 수 있다. 중간 항목을 제거하려면 제거하는 항목 이후의 모든 항목을 한 칸씩 앞으로 당기거나 죽은 공간으로 표시해야 한다.

연결 리스트(linked list)

  • 저장한 칸들을 쇠사슬처럼 연결한 구조이다.
  • 장점 - 배열과 달리 연속적인 메모리 주소로 구성될 필요가 없다. 처음부터 필요한 모든 메모리를 할당해 둘 필요가 없다. 리스트 중간에 추가, 삭제가 간단하다.
  • 단점 - 배열과 달리 n번째 항목을 상수 시간에 가져오지 못한다. 어느 한 칸의 주소만 가지고 해당 항목을 삭제하거나 앞쪽으로 옮기기 어렵다.(각 칸은 다음 칸의 주소만 알고 있어, 이전 칸의 주소를 구할 수 없기 때문에)

이중 연결 리스트(double linked list)

  • 각 칸이 갖는 포인터를 2개로 늘려, 각각 이전 다음 칸을 가리키도록 한 것
  • 연결 리스트의 장점을 그대로 가진다.
  • 단점 - n번째 항목에 상수 시간 접근 불가. 2개의 포인터로 인해 코드 복잡 데이터 저장하는데 메모리 늘어남.

배열 VS 리스트

- 연결 리스트를 사용해야 하는 경우

  • 리스트에서 항목의 추가, 제거가 아주 빠르게 수행되어야 한다.
  • 데이터에 순차적으로만 접근한다.
  • 리스트의 중간에 항목의 추가, 제거를 수행해야 한다.
  • 리스트의 정확한 크기를 계산할 수 없다(실행 도중에 리스트가 확대, 축소되어야 한다.)

- 배열을 사용해야 하는 경우

  • 데이터의 임의의 지점으로 상수 시간에 접근해야 하는 경우가 잦다.
  • 항목에 아주 빨리 접근해야 한다.
  • 실행 도중에 항목 개수가 변하지 않으므로 컴퓨터 메모리 공간을 연속적으로 할당하기 쉽다.

트리(tree)

  • 연속적인 물리적 메모리가 필요 없다.
  • 다른 칸을 향한 포인터를 가짐.
  • 계층형 구조이다.

트리 종류 

- 이진 탐색 트리(binary search tree)

  • 효율적인 탐색을 지원하는 트리
  • 각 노드가 자식을 2개까지만 가질 수 있음.
  • 노드의 위치는 노드의 키-값에 의해 결정된다. 부모 노드의 왼쪽 자식 노드는 부모 정점보다 키-값의 크기가 작아야 하고 오른쪽은 커야 함.

* 이진 탐색 트리에 정점을 너무 많이 추가하면, 자식이 하나뿐인 정점이 많이 생기면서 트리의 높이가 터무니없이 높아진다.(연결 리스트에 가까운 형태) 따라서, 재배열해야 하는데 이를 '트리 균형 잡기'라 한다.

* n개의 균형 잡힌 이진 탐색 트리를 탐색하는 시간 복잡도는 O(logn)이다.

* 트리에 항목이 추가, 제거될 때마다 균형을 새로 잡는다면 성능이 크게 떨어지므로 대개 여러 번의 추가, 제거 연산이 일어난 후에 균형을 잡는다.

 

- 자가 균형 이진 탐색 트리 : 레드 블랙 트리(red-black tree)

  • 정점들을 레드 또는 블랙으로 칠함으로써 균형을 유지.
  • 맵을 구현 하는데 자주 사용된다. 맵의 빈번한 수정을 효율적으로 처리.
  • 자가 균형을 통해 키로 항목을 구하는 작업 빠름.

- 자가 균형 이진 탐색 트리 : AVL tree

  • 레드 블랙트리에 비해 항목 추가 제거 시간이 조금 더듬 대신 균형을 더 잘 잡는 경향이 있음 즉 항목의 조회 속도가 빠름.
  • 읽기 작업이 매우 높은 빈도로 일어나는 상황에 성능 최적화.

- 이진트리 : B트리

  • 각정점이 하나 이상의 항목 저장 자식도 둘 이상씩 연결 따라서 큰 덩어리의 데이터 효율적 처리.
  • 데이터베이스 시스템에 보편적 사용.

- 이진 탐색 트리 : 이진 힙(binary heap) 

  • 최대(최소) 항목을 즉시 구할 수 있는 특별한 이진 탐색 트리. 특히 우선순위 큐를 구현할 때 유용.
  • 최대(최소) 구하는 비용은 O(1), 노드의 탐색 추가 비용은 O(logn).
  • 힙의 노드 배치 규칙은 이진 탐색 트리와 동일하나 제약이 하나 추가됨.
  • 제약 : 부모 노드가 반드시 두 자식 노드보다 커야(또는 작아야) 한다.

그래프

  • 트리와 유사한 데이터 구조. 다른 점이라면 자식, 부모 노드가 없음.
  • 정점과 간선으로 자유롭게 배열될 수 있음.
  • 네트워크 연결망을 다루어야 한다면 그래프!

그래프 탐색

  • 깊이 우선 방식(DFS, depth-frist search) - 스택 사용. 구현 쉬움 메모리 적게 사용.
  • 너비 우선 방식(BFS, breadth-frist seaarch) - 큐를 사용. 구현 어려움. 많은 메모리 사용.
  • 탐색하려는 정점이 출발점에서 몇 단계밖에 떨어지지 않았다고 예상되는 상황에서는 너비 우선 탐색 아니면 깊이 우선 탐색.
  • 다익스트라 알고리즘(Dijkstra algorithm) - 그래프 최단경로 탐색 알고리즘(GPS 내비게이션 시스템). 큐 대신 우선순위 큐 사용. 하지만 음의 폐로(negative cycle)가 발생할 수 있음. 간선에 0보다 작은 가중치가 존재해 출발점과 도착점이 서로 연결되는 순환 경로가 생길 수 있음. 음의 폐로에서는 같은 경로를 계속 되돌기 때문에 목적지에 도달 불가능 그러므로 음의 가중치를 갖는 간선이 있다면 주의가 필요하다.
  • 양방향 탐색 기법 - 탐색하려는 그래프가 매우 방대할 때 사용. 출발점과 도착점에서 탐색을 동시에 시작하여 두 탐색 범위가 겹친다면 완료.
  • 페이지 랭크(OageRank algorithm) - 구글 검색 알고리즘. 어떤 페이지가 다른 중요한 페이지로부터 많이 링크된다면 링크된 페이지 역시 중요한 페이지이다. 이 알고리즘은 페이지를 그래프로 나타내고 여러 라운드에 걸쳐 페이지의 점수 평가. 처음에는 모든 페이지가 동일한 점수를 가지만 라운드가 진행될 때마다 페이지들은 자신이 획득한 점수를 자신이 링크하는 페이지에 나누어줌. 이 분배과정에서 점수가 안정화될 때까지 계속 반복.

해시 테이블(hash taable)

  • 탐색을 O(1) 비용으로 수행할 수 있는 데이터 구조.
  • 대량의 연속적 메모리를 미리 할당 하지만 배열과 다르게 항목을 순차적을 저장하지 않음.
  • 해시함수에 의해 정해짐.
  • 맵과 집합을 구현하는데 자주 사용.
  • 장점 - 항목의 추가 제거가 트리 기반의 데이터 구조에 비해 빠름.
  • 단점 - 올바르게 동작하기 위해 대량의 연속적 메모리 공간 필요.

해시 함수 

  • 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수
  • 같은 입력값에 대해서 같은 출력값이 보장된다.
  • 서로 다른 입력값으로부터 동일한 출력값이 나올 가능성이 희박해 입력값에 대한 무결성이 보장
  • 일방향성을 갖는다. (출력값으로 입력값을 추론 불가)
  • 좋은 해시 함수의 조건 : 계산이 간단해야 한다. 입력 원소가 해시 테이블 전체에 고루 저장되어야 한다.

* 해시 함수의 대표 - SHA(Secure Hash Algorithm)

  • NSA에 의해 1993년 처음 개발된 해시 알고리즘
  • 현재 주로 사용되는 것은  SHA-2 함수 군으로, SHA-256, SHA-512으로 나뉜다.
  • SHA-256, SHA-512는 해시 충돌성이 사실상 0에 수렴.(해싱을 하면 2^256개의 해시값 중 하나가 나옴)
  • 무결성 검사, 파일 다운로드, 데이터베이스에 비밀번호 저장, 블록체인,  GIT등에 활용됨

해시 충돌

  • 우연히 두 개의 입력값에 동일한 해시값이 나옴
  • 해시함수가 내어놓는 값의 범위(해시 테이블에 할당된 메모리의 크기)가 넓을수록 데이터가 분포될 수 있는 범위가 더 많아지고 해시 충돌이 일어날 가능성도 줄어듦. 따라서 해시 테이블의 최소 공간을 50%는 남겨 두어야 함. 그렇지 않으면 충돌이 너무 자주 발생해 해시 테이블의 성능이 심각하게 떨어짐
  • 해시 함수는 일반적으로 다양한 크기의 데이터를 입력받아 일정한 크기의 값을 출력. 서로 다른 데이터로 해시 함수를 적용해도 결과가 동일할 수 있음

해시 충돌 해결 방법

1. 체이닝(chaining) 

  • 같은 주소로 해싱되는 원소를 모두 하나의 연결 리스트에 매달아서 관리한다.
  • 원소를 검색할 때는 해당 연결 리스트의 원소들을 차례로 지나가면서 탐색한다.

2. 개방 주소 방법(open addressing)

  •  체이닝과 달리 어떻게든 주어진 테이블 공간에서 해결한다.
  • 따라서 모든 원소가 반드시 자신의 해시값과 일치하는 주소에 저장한다는 보장이 없다.
  • 선형 조사(linear probing), 이차원 조사(quadratic probing),  더블 해싱(double hashing)

2-1. 선형 조사(linear probing)

  • 가장 간단한 충돌 해결 방법
  • 충돌이 일어난 자리에서 일차 함수의 보폭으로 점프한다.
  • 테이블의 경계를 넘어갈 경우에는 맨 앞으로 돌아간다.

2-2. 이차원 조사(quadratic probing)

  • 바로 뒷자리를 보는 대신 보폭을 이차 함수로 넓혀가면서 본다.

2-3. 더블 해싱(double hashing)

  • 두 개의 함수를 사용한다.
  • 하나의 함수는 초초의 해시값을 얻을 때, 다른 하나의 함수는 해시 충돌이 일어났을 때 이동할 폭을 얻을 때 사용
  • 두 원소의 첫 번째 해시값이 같더라도 두 번째 해시값까지 같을 확률은 매우 희박하므로 서로 다른 보폭으로 점프

 

출처 - 한 권으로 그리는 컴퓨터 과학 로드맵 / 블라드 스톤 페헤이라 필루 

 

'Study > 정리' 카테고리의 다른 글

RAID  (0) 2021.04.11
절차 지향  (0) 2021.04.02
시간 복잡도  (0) 2021.04.02
컴포넌트, 모듈, 프로시저  (0) 2021.04.02
[IntelliJ] Spring Framework Tomcat 설정하기  (0) 2021.03.08
Comments