4 분 소요

1) 자료구조란?

  • 자료를 효율적으로 사용하기 위해서 자료의 특성에 따라서 분류하여 구성하고 저장 및 처리하는 모든 작업
  • 궁극의 효율을 가진 자료구조는 존재하지 않음
  • 요구사항에 의존적으로 선택

image

2) 배열과 리스트

  • 배열
    • 동일한 형태의 자료
    • 메모리에 연속으로 정적 할당
    • 단순하지만 처리 효율은 떨어짐
  • 연결 리스트
    • 재귀적 자료 구조
    • 메모리에 불연속적으로 동적 할당
    • 복잡하지만 처리 효율 우수
  • 배열과 리스트의 차이
    • 배열은 연속된 메모리 공간으로 한번 할당하면 메모리 크기 변경이 용이하지 않다.
    • 리스트는 필요할 때 메모리를 할당하여 데이터를 저장할 수 있어 메모리 관리 차원에서는 배열보다 효율적이다.
    • 리스트에서 메모리 블록은 연속적이라는 보장은 없다.

3) 알고리즘 (Algorithm)

  • 컴퓨터로 문제를 풀기 위한 단계적인 절차
  • 조건
    • 입력 : 0개 이상의 입력이 존재해야한다.
    • 출력 : 1개 이상의 출력이 존재해야한다.
    • 명백성 : 각 명령어는 모호하지 않고, 명확해야 한다.
    • 유한성 : 한정된 수의 단 후에는 반드시 종료되어야 한다.
    • 유효성 : 각 명령어들은 실행 가능한 연산이어야 한다.

4) 컨테이너

  • 대부분의 일반적 추상형 데이터 타입 (ADT : Abstract Data Type)
    • 내용물이 무엇으로 구성되어 있는지 상관하지 않고 컨테이너에 보관한다.
  • 객체에 접근하고 저장하는 등의 자료의 구조를 묘사함

컨테이너의 연산

  • 컨테이너 생성
  • 기존 컨테이너의 복사나 폐기
  • 컨테이너 비움
  • 컨테이너 내 객체의 개수 반환
  • 컨테이너가 수용할 수 있는 최대 객체의 수 반환
  • 두 컨테이너에서 합집합, 교집합 계산

컨테이너에 저장된 객체의 연산

  • 객체의 삽입
  • 객체에 접근 혹은 수정
  • 객체의 삭제
  • 컨테이너 내에 존재 유무 확인
  • 컨테이너 내 객체 모두를 반복 (혹은 한번에 하나씩 한꺼번에 접근)
#include <iostream>
#include <set>

using namespace std;

int main()
{
	// Ignores duplicates: (-3)*(-3) == (3)*(3)
	set<int> ints;
	
	for (int i = -100; i <= 100; i++)
	{
		// insert result : 101 value (0, 1, 4, 9...10000)
		ints.insert(i * i);		
	}

	cout << "Size of 'is' : " << ints.size() << endl;

    
	ints.erase(50); // Does nothing
	ints.erase(9);  // Remove 9
	cout << "Size of 'is' : " << ints.size() << endl;

	return 0;
}

5) 관계와 순서

관계

  • 객체 간의 관계
  • 관계를 기반으로 추가적 연산 수행
  • 탐색
    • 저장 뿐 아니라 객체의 개수에 관계없이 빠르게 처리할 수 있는 자료 구조 필요
    • Hash 함수를 사용한다.
  • 종류
    • 선형 순서
    • 단계적 순서
    • 부분 순서 : 전체가 아닌 부분적으로 관계가 형성
    • 동치 관계 : 모양은 다르지만 내부적으로 동일하다.
    • 약한 순서 : 두 객체간의 강하고, 약한 관계
    • 인접 순서 : 인접한 객체와의 관계
  • 논리적 연산
    • 같은가? x = y
    • 작은가? x < y
    • 나누어 지는가? x | y

순서 (선형적)

  • 관계가 추이적일 때, 다음 세가지 중 하나인 경우로 비대칭 관계
    1. x > y
    2. x < y
    3. x = y
  • 선형적 순서 관계
    • 정수 : 1, 2, 3, 4, 5…
    • 실수 : 1.2, 1.2001, 1.24, 1.35…
    • 문자 : a, b, c, d, e, f…
    • 메모리 : 0x0000, 0x0001…
  • 사전적 순서 관계
    • 순서화된 영어 단어의 집합 : 순서는 첫글자 비교
  • 계층적 순서 관계
    • 파일 시스템에서의 디렉토리 : x가 y를 서브 디렉토리로 가지고 있음

6) 추상 데이터 형 (ADTs : Abstract Data Types)

  • 공학적 관점에서 반복되는 어떤 패턴들이 존재
  • 우선 패턴을 명명하고 표준 해답 혹은 구현 방법을 정의
  • 제한된 처리와 연산의 객체와 연관된 관계가 구현된 컨테이너가 존재
  • 이 컨테이너를 모델링 한 것
  • 요구사항
    • 어떤 관계가 있는가?
    • 어떤 처리, 연산이 필요한가?
    • 어떤 관계적 처리, 연산이 필요한가?
  • 구현
    • Hash Table 자료 구조
    • 순서화된 리스트
    • 배열이나 연결 리스트는 비효율적

7) 메모리 할당의 개념

연속적(Contiguous) 할당 : 배열

  • 하나의 배열로서 단일 연속적인 메모리 공간에 n객체가 저장된다.
  • 더 많은 메모리가 필요할 때에는 새로 메모리 공간을 할당 받고, 모든 정보를 복사해야 한다.
  • 일반적으로 OS에게 추가로 연속된 n객체의 공간을 할당 받을 수 없다.

연결적(Linked) 할당 : 연결 리스트

  • 두 데이터를 연결적으로 저장할 수 있도록 할당한다.
  • 객체 자기 자신 그리고 자신과 연결되어 있는 다음 아이템에 대한 참조로 구성한다.
  • C++ 객체에서의 노드란 다음 노드의 주소를 지칭한다.
template <typename Type>
class Node 
{
    private:
        Type element;
        Node *next_node;
    public:
    // ...
};
  • 연산방법
    • 새로운 노드의 생성
    • 노드의 값을 읽음
    • 다음 포인터를 가져옴
Node(const Type& = Type(), Node* = nullptr);
Type retrieve() const;
Node *next() const; 
  • 필수항목
    • 연결 리스트는 반드시 첫 번째 객체를 가리키는 객체가 필요하다.
    • 실제로 연결 리스트 클래스는 머리(head)와 꼬리(tail), 두 포인터를 반드시 가지고 있어야 한다.
    • 선택적으로 노드의 개수(int count)를 가질 수 있다.
    • Next_node의 마지막 노드는 nullptr로 저장한다.

image

  • 클래스의 구현
    template <typename Type>
    class List {
      private:
          Node<Type> *head;
          Node<Type> *tail;
          int count;
      public:
          // constructor(s)...
          // accessor(s)...
          // mutator(s)...
    };
    

색인적(Indexed) 할당

  • NULL을 포함하여 포인터의 배열이 할당된 메모리 공간을 가리킨다.
  • C++ STL(Standard Template Library)에서 사용한다.
  • 색인적 할당은 행렬로 표현할 수 있다.

image

  • 대부분 행렬은 단일로 연속된 메모리 공간을 가리키는 색인을 사용하여 구현할 수 있음

image

8) 다른 할당 형식

트리(Tree)

  • 트리는 연결 리스트의 변형으로서 여러 개의 다음 포인트를 가진다.
  • 각 노드는 임의의 개수의 다음 노드를 가리킨다.
  • 계층적 데이터의 저장에 유용하다.
  • 정렬된 데이터의 저장에 유용하다.
  • 보통의 경우 다음 노드의 개수를 두 개 이하로 제한한다

image

그래프(Graph)

  • 한 컨테이너에서 두 객체 간의 임의의 관계를 허용한다고 가정하자.
  • 대칭성을 허용한다면
    • n개의 객체가 있다면 (n*n - n)개의 가능한 관계가 존재한다.

image

배열(Array)

  • 한 컨테이너에서 두 객체 간의 임의의 관계를 허용한다고 가정하자.
    • 이를 2차 배열을 이용하여 표현할 수 있다.
    • 이 때 이 행렬은 대칭행렬이다.

image image

연결리스트의 배열(Array of Linked Lists)

  • 한 컨테이너에서 두 객체 간의 임의의 관계를 허용한다고 가정하자.
    • 배열과 연결 리스트의 혼합 형식을 사용할 수 있다.

image image

연결 배열(Linked Array)

  • 다른 혼합 형식으로 배열의 연결 리스트가 있다.
  • 이는 C++ STL의 Dequeue 컨테이너로 사용된다.

image

혼합 구조(Hybrid Structure)

  • Unix의 Inode는 대용량의 파일 정보를 저장하는데 사용되었다.
  • 다음 개체는 다음 1024 블록을 저장할 수 있는 배열을 참조한다.
  • 32-bit 컴퓨터에서 최대 4MB 용량의 파일을 저장한다.

image

9) 알고리즘의 효율성

정렬된 배열의 연산 효율표

image

비정렬 배열의 연산 효율표

image

연결리스트의 연산 효율표

image

이중 연결리스트의 연산 효율표

image

10) 알고리즘의 분석

  • 공간적 효율성과 시간적 효율성
    • 공간적 효율성은 얼마나 많은 메모리 공간을 요하는가를 말한다.
    • 시간적 효율성은 얼마나 많은 시간을 요하는가를 말한다.
    • 효율성을 뒤집어 표현하면 복잡도(Complexity)가 된다. 복잡도가 높을수록 효율성은 저하된다.

빅 오(Big O)

  • 효율을 분석하기 위해 사용되는 수학적 도구
  • 조건
    • 시간적 복잡도를 데이터 크기 N의 함수로 표시하되 계수를 무시한다.
    • N이 무한대로 갈 때를 기준으로 평가한다.
    • 입력 데이터가 최악일 때 알고리즘이 보이는 효율을 기준으로 한다.
  • 임의의 상수 N0와 c가 있어서 N≥N0인 N에 대해서 image

업데이트: