달력

52025  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

'자료구조'에 해당되는 글 3건

  1. 2009.11.06 자료구조(해싱)
  2. 2009.11.06 자료구조(Stack 과 Queue)
  3. 2009.11.06 자료구조 ( Array와 Linked List)-

자료구조(해싱)

자료구조 2009. 11. 6. 15:21


◎ 해싱에대해서?

○ 해싱이란?

해시 함수를 이용하여 키 값을 위치로 변환하고 이를 이용해
저장된 자료를 바로 찾아가는 계산 검색 방식이다.
값의 연산에 의해 직접 접근이 가능한 구조를 해시테이블(hash table)
해시테이블을 이요한 탐색을 해싱(hashing)

 

○ 해싱구조..

레코드 키들의 집합을 버켓주소의 집합에 대응시킨다는 의미에서 사상함수라 한다.
가장 이상적인 해싱 함수는 키 집합의 한 레코드와 버켓 주소 집합의 한 레코드가
1 : 1 대응하여 해시 테이블의 정해진 범위에 고르게 분포되어 있는것을 뜻함.

-저장 및 검색 과정-

키 값 –> 해싱 함수 –> 해시 주소(버킷 주소) –> 해시 테이블

 

해싱 함수 구현부분-
----------------------------------------------------------------------------------------
public static int hash(Object key) // hashing method >> private
{   
  int sum = 0;
  byte compare[] = null;
     compare=((String)key).getBytes(); // 문자열을 바이트로 환산해주는 메서드 >> 리턴값 : 배열
   
  for(int i=0;i<((String)key).length();i++)
  {
  sum+=(int)compare[i];
  }
    
  int h=(sum & 0x7FFFFFFF) % capacity;
  return h;
 }
------------------------------------------------------------------------------------------


○ 해시 테이블

해상함수로부터 계산된 함수값에 해당하는 위치에 각 레코드를 한 개 이상 보관할 수 있는
버켓들로 구성된 기억 공간이며, 주어진 key값을 가지고 해당 레코드를 빠르게 검색하기 위한
수단을 제공하며 레코드의 삽입과 삭제를 용이하게 한다.

해시 테이블은 크기가 파일보다 커야한다. n개의 레코드에 대해 n개의 해쉬 주소를 생성
하는 해쉬 함수를 찾는것은 불가능 하기 때문.
일반적으로 부하율(load factor) 75%이상이면 일정의 테이블 공간을 늘려주는 것이 좋다.
그이상의 급격하게 성능 저하가 발생!!

 

○ 버켓

일종의 자료구조로 해싱함수에 의해 계산된 주소인 홈 주소에 레코드를 저장하기 위해 마련된 기억공간.

 

○ 해싱함수란?

탐색 키를 간단화하는 함수를 해싱 함수(hashing function) 라 하며,
탐색 키를 받아서 해시 주소를 생성하는 기능을 한다.
이 해시 주소가 바로 간단화된 탐색 키라고 할 수 있고. 자리수가 몇 안 되는 정수이고 곧 배열의 번호이다.


※ 좋은 해시 함수 조건
- 주소 계산이 빠르게 구해져야 한다.
- 서로 다른 레코드의 계산된 값이 가급적 중복되지 안하야 한다(충돌이 적어야한다)

○ 해싱함수의 종류

-제산법(Division) : 나머지 연산자(%)를 사용하여 테이블 주소를 계산하는 방법!!
                    * 버켓주소 = 키 값 % 해쉬테이블 크기


-제곱법(Mid-Saure) : 레코드 키 값을 제곱한 후에 결과 값의 중간 부분에 있는 몇 비트를
                     선택하여 해시 테이블의 홈 주소로 사용, 심볼 테이블 응용에서 자주 사용
                    * k = 35270 제곱시 테이블의 크기가 10,000일때(중간 4비트선택)
         11243972900 -> 1243ㅣ9729ㅣ00 -> 9729가 주소값


-숫자 분석법(Digit-Analysis) : 레코드 모든키들 내에서 각 자리별로 어떤 분포인지 조사하여
          비교적 고른 분포를 나타내는 자릿수를 필요한 만큼 선택하여 사용
                               * 정적 파일에 유효, In/out 빈번히 발생할경우 비효율적

 

-폴딩법(Folding) : 레코드 키의 마지막 부분을 제외한 모든 길이가 동일하게 여러부분으로 나누고
                   이를 모두 더하거나 배타적 노리합을 취하여 홈주소로 이용하는 방법

  탐색키 : 123ㅣ203ㅣ241ㅣ112ㅣ20
                  
  *이동폴딩 : 각부분의 값을 계산하기 위해 마지막을 제외한 모든 부분을 이동시
        최하위 비트가 마지막 부분의 자리와 일치하도록 우측끝을 맞추어 더한 값

        123+203+241+112+20 =699      


  *경계폴딩 : 나누어진 각 부분의 경계선을 종이 접듯이 접어 역으로 정렿한 다음 더한 값

        123+302+241+211+20=897

                    
- 기수변환법 , 무작위 방법 등이 있음

 


○ OverFlow 해결

- 선형조사법,이차조사법,이중해싱법,체이닝 의 방법 사용 (선형법과 체이닝 많이사용)

* 선형 조삽법(선형 개방 주소법) : 충돌이 일어난 키값을 다른 비어있는 버킷을 찾아 저장한다.
       이 때 비어있는 버킷은 순차적으로 찾는다

 

* 체이닝(Chaining) : 오버플로우 문제를 연결 리스트로 해결
        각 버켓에 고정된 슬롯을 할당하는 것이 아니라 각 버켓에, 삽입과 삭제가
        용이한 연결리스트를 할당
        버켓내에서는 원하는 항목을 찾을때는 연결리스트를 순차 탐색!

 


○ 동적 해싱법

 해시 테이블 대신에 트라이라는 자료구조 사용
 트라이 : 입력키의 각 비트값에 따라 2개의 가지로 분리되도록 만들어진 것
 
 키 값의 맨 오른쪽 비트부터 검사 하여 0일경우 첫번째 레벨의 위쪽 1일경우 아래쪽 으로 분기
 끝에서 두번째 비트를 검사하여 그값이 0이면 두번째 레벨의 위쪽 1이면 아래쪽으로 분기
 ......순차적으로 오른쪽에서 왼쪽으로 키값을 비교해 나가면서 분기한다.,

------------------------------------------------------------------------------------------------------------------------

구현

----Entry Class---------------------------------------------------------------------------------------------------------

public class Entry
{
 public Object key, value; //key,value 필드 분리
 public Entry next;  // Node 개념 적용 - 자기 참조

 public Entry(Object key, Object value) {
      this.key = key;
      this.value = value;
    }

 public Object getKey() {  //key 리턴
      return key;
    }
   
 public Object getValue() {  //value 리턴
       return value;
    }

 public void setValue(Object value) { //value 설정
      this.value = value;
    }
}


----HashTable Class----------------------------------------------------------------------------------------------------

public class HashTable
{
   private static final int CAPACITY = 10;  //기본테이블 크기
   private static int capacity;
   public Entry[] hTable;  // 해쉬테이블은 배열로 구성되어 있고 각각의 배열에는 엔트리가 들어감 

   public HashTable(int capacity) // 파라미터가 테이블 용량을 넘겨줄경우 생성자
   { 
     this.capacity = capacity;
     hTable = new Entry[capacity];  // 테이블 크기만큼 엔트리 생성 해서 해쉬 테이블 생성
   }

   public HashTable() // 파라미터가 없을경우
   {   
     this(CAPACITY);  // 기본값 크기로
   }

   public static int hash(Object key) // hashing method >> private
   {   
     int sum = 0;
     byte compare[] = null;
     compare=((String)key).getBytes(); // 문자열을 바이트로 환산해주는 메서드 >> 리턴값 : 배열
    
     for(int i=0;i<((String)key).length();i++)
     {
      sum+=(int)compare[i];
     }
    
     int h=(sum & 0x7FFFFFFF) % capacity;
     return h;
  }

  
   public void put(Object key, Object value) // 넣기
   { 
     int h = hash((String)key);   // key 값으로 해싱
     Entry cur = hTable[h];  // 해싱값에 해당하는 배열칸값
     Entry entry = new Entry(key, value); // 엔트리 형성
    
     if (hTable[h] == null) //
      { 
       hTable[h] = entry;    // 입력된 값 저장
      }
     else {  // 해시값 충돌시
         while (cur.next != null)// 노드 끝까지
          {      
            if(cur.getKey().equals(key)) // 혹시나 키값이 같은 자료 입력을 시도랬다면
            {  
            cur.setValue(value);   // 해당엔트리의 자료값만 변경
            break;  // 그다음 끝냄
            }
           cur = cur.next;    // 리스트가 끝날때까지 next 로 찾아감
          }
         cur.next = entry;   // 리스트의 끝에 입력된 엔트리 달기
        }
   }
   


  public void searchMap(Object word) // 검색 메서드
  {  
   int flag = 0; // 결과 상태
   Object result = null; // 결과값
   Entry cur = hTable[hash(word)];
  
   if (cur == null)
    flag = 0;
   else
   {
    while(cur != null)
    {
     if (cur.getKey().toString().equals((String)word))
      {
      flag = 1;
      result = cur.getValue(); break;
      }
     else
      cur = cur.next;
    }
   }
  
   //검색결과 출력
   if (flag == 0 ) System.out.println("검색결과가 없습니다.");
   else System.out.println("검색결과가 있으며 값은 " + (String)result + " 입니다.");
  }
 
 

   public void printMap() // 출력
   { 
     Entry cur;                   // 출력할 엔트리를 '포인팅' 하기 위해 정의한 변수
     for(int i=0; i<capacity; i++) // 테이블 크기 수 만큼
     { 
       System.out.print("|"+i+"|\t"); 
       cur = hTable[i];     // i번 배열에 있는 엔트리를 받아오기
      
       if((cur == null))        // 비어있을경우
        System.out.print("null");  // null 출력
       else
       { 
         while(cur != null)
         {      // 엔트리 끝이 더이상 없을 때까지
           System.out.print("Key : "+ cur.getKey() +"  Value : "+ cur.getValue()+"  ");  // 현재 엔트리의 키값과 자료값을 불러와 출력
           cur = cur.next;        // 다음번 엔트리로 넘어가기
         }
       }
       System.out.println("");   // 줄바꾸기 
     }      
   }
  
  
 }

----Testinput Class-----------------------------------------------------------------------------------------------------

public class Testinput
{

 public static void clearScreen() // 화면 초기화
 {
      for (int i = 0; i < 80; i++)
        System.out.println("");
 }
 
 
 public static void main(String[] args) throws IOException
 {
     HashTable map2 = new HashTable();
  int msel;
        String con;  // 계속 여부
        do
        {
          //clearScreen();
    System.out.println("메뉴를 선택하세요");
    System.out.println("1. 입력");
    System.out.println("2. 출력");
    System.out.println("3. 검색");
    System.out.println("4. 종료");
    
    BufferedReader ar = new BufferedReader(new InputStreamReader(System.in));
    msel =Integer.parseInt(ar.readLine());
    
    switch (msel)
    {
     case 1: // 입력
     {
      System.out.println("key : ");
      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
      String b=br.readLine().toString();
      System.out.println("value : ");
      BufferedReader cr = new BufferedReader(new InputStreamReader(System.in));
      String c=cr.readLine().toString();
      map2.put(b,c);
      break;
     }
     case 2: // 출력
     {
      map2.printMap();
      break;
     }
     case 3: // 검색
     {
      System.out.println("search : ");
      BufferedReader dr = new BufferedReader(new InputStreamReader(System.in));

      String d=dr.readLine().toString();
      map2.searchMap(d);
      break;
     }
     case 4: // 종료
     {
      return;
     }
    }     
  
  } while (true);
  
  
  
 }

}

----TestChaining Class--------------------------------------------------------------------------------------------------

public static void main(String[] args)
{
     HashTable map1 = new HashTable();  // 첫번째 맵 형성
     map1.put("태희","011-234-5348");  // 자료입력
     map1.put("미","011-214-7678");
     map1.put("동훈","015-434-8378");
     map1.put("종훈","011-2674-5878");
     map1.put("Hut","016-214-2678");
     map1.put("Ohr","013-134-1678");
     System.out.println("map1 is  ");
     map1.printMap();  // 자료출력
    
     map1.searchMap("Ohr");
     map1.searchMap("종훈");
    


     //System.out.println(map1.hash("Tor"));
     //System.out.println(map1.hash("Rad"));
    
    
    

     HashTable map55 = new HashTable();
     map55.put("a","1234");
     map55.put("b","3456");
     map55.put("c","9874");
     map55.put("d","5478");
     map55.searchMap("c");
    
    
   }
 }


------------------------------------------------------------------------------------------------------------------------LRU 기법? 주기억장치에 저장된 시점과 관계없이, 사용률이 가장 저조한 페이지를 교체하는것!

'자료구조' 카테고리의 다른 글

자료구조(Stack 과 Queue)  (0) 2009.11.06
자료구조 ( Array와 Linked List)-  (0) 2009.11.06
Posted by 인천총각
|

◆◆ Stack 과 Queue


◆ 1. Stack

  ㉠ 정의

      여러 개의 데이타 항목들이 일정한 순서로 나열된 자료 구조로, 한쪽 끝에서만 새로운 항목을 삽입하거나 기존 항목을 삭제할 수
      있는 선형 구조.


  ㉡ 특징

      Last- In-First-Out List (후입 선출) : 먼저 삽입된 것은 나중에 삭제되고, 나중에 삽입된 것이 먼저 삭제.

      push : Data 를 넣는 것.

      pop : 넣어둔 Data 를 꺼내는 것.

      top : Data 를 저장하는 위치


  ㉢ 연산

       S를 스택, x를 데이터 요소(element)라고 하자. 그러면 스택에서는 아래와 같은 중요한 연산이 존재하는 것을 알 수 있다.

       S.top(): 스택의 가장 윗 데이터를 넘겨준다.만약에 비었다면 이 연산은 정의불가 상태다.

       S.pop(): 스택의 가장 윗 데이터를 지우고 그 값을 넘겨준다.스택이 비었다면 연산 정의불가 상태.

       S.push(): 스택의 가장 윗 데이터로 x를 넣는다.

       S.empty(): 스택이 비었다면 참을 주고,그렇지 않다면 거짓이 된다.

       또한, 스택연산을 목록(list) 연산으로 표현할 수도 있다.

       S.top(): S.retrieve(S.first())

       S.pop(): S.top(),S.delete(S.first())

       S.push():S.insert(x,pNull)

       S.empty():S.first()==pNull

 

◆ 2. Queue

  ㉠ 정의

      여러 개의 데이타 항목들이 일정한 순서로 나열된 자료 구조로 한쪽 끝에서는 삽입만 할 수 있고, 삭제는 반대쪽 끝에서만 할 수 있
      도록 되어 있는 선형 구조.


  ㉡ 특징

       First In First Out (선입선출) : 큐에 저장된 데이터 항목들 중에 먼저 삽입된 것은 먼저 삭제되고, 나중에 삽입된 것은 나중에 삭제.

       put : Data 를 넣는 것.

       get : Data 를 꺼내는 것.

       front(head) : Data 를 put 할 수 있는 위치.

       rear(tail) : Data 가 있어 get 할 수 있는 위치.

       Overflow : Queue 가 꽉 차서 더 이상 Data 를 넣을 수 없는 경우 (put 할 수 없는 경우)

       Underflow : Queue 가 비어 있어 Data 를 꺼낼 수 없는 경우 (get 할 수 없는 경우)


  ㉢ 종류

       가. 선형 Queue : 막대 모양으로 된 Queue 이다. 크기가 제한되어 있고 빈 공간을 사용하려면 모든 Data 를 꺼내거나 Data 를 한
                               칸씩 옮겨야 한다는 단점이 있다.

       나. 환형 Queue  : 선형 Queue 의 문제점을 보완한 것이 환형 Queue 이다. front가 Queue 의 끝에 닿으면 Queue 의 맨 앞으로 Data 를 보내어 원형으로 연결 하는 방식.

       다. Linked Queue  : Linkedlist 를 사용한 것으로써, Queue  의 길이를 쉽게 늘릴 수 있어 Overflow 가 발생하지 않는다.

                                  필요에 따라 환형으로 만들 수도 있으며, 환형으로 만들지 않아도 삽입과 삭제가 제한되지 않아 편리하다.

 

◆◆ 3. Simulation (Java)


1. node 클레스 설계
------------------------------------------------------------------------------------------------------------------
public class Node {
 
 public Node(int v){
  value = v;
 }
 
 public int value;
 public Node next;   // 자기 참조!!
}
------------------------------------------------------------------------------------------------------------------

 

2. LinkedList 클레스 설계
------------------------------------------------------------------------------------------------------------------
public class LinkedList {
 Node header;

 public LinkedList(Node h) {
  header = h;
 }

 public void append(Node node) {
  Node last = header;
  while (last.next != null) {
   last = last.next;
  }
  last.next = node;
 }
 
 public Node getHeader(){
  return header;
 }

 public void remove_back() //링크드 리스트에 뒤에 있는걸 삭제
 {
  Node last = header;

  if (last.next == null)  // elements 가 하나만 있는 상황이므로 끊을필요 없다
  {
  }
  else
  {
   while (last.next.next != null) { // 두번째 연결된 elements 의 next 값이 없을때 까지 루프
    last = last.next;
   }
   last.next = null; //  마지막 에 연결된 elements 의 next 를 null 값을 넣어 끊기
  }
 }
 
 public void remove_front() //링크드 리스트에 앞에 있는걸 삭제
 {
  header = header.next; // 헤더 를 다음 값으로 바꾸기
  
 }
  
}
------------------------------------------------------------------------------------------------------------------

 

3. Array 로 Stack 구현
------------------------------------------------------------------------------------------------------------------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class IntStack_A {
 
    private int[] data;

    private int top;   // stack 맨위

    private int many_items; // 현재 Stack 에 몇 개의 원소가 있는지를 저장해 놓은 변수

    private int stack_size; // Stack 의 전체 크기
   
    private BufferedReader br ;

public IntStack_A(int size) // size : 스텍의 크기
    {
        data = new int[size];

        stack_size = size;      

        top = -1; // stack 이 비어 있을 때

        many_items = 0;

     System.out.println("값을 입력하세요 :");
     try {
      br = new BufferedReader(new InputStreamReader(System.in));
      push(Integer.parseInt(br.readLine()));
      br = new BufferedReader(new InputStreamReader(System.in));
      push(Integer.parseInt(br.readLine()));
      br = new BufferedReader(new InputStreamReader(System.in));
      push(Integer.parseInt(br.readLine()));
      br = new BufferedReader(new InputStreamReader(System.in));
      push(Integer.parseInt(br.readLine()));

   printf1();   
   System.out.println("");
   System.out.println("1.삭제(POP)  2.삽입(PUSH)");
   br = new BufferedReader(new InputStreamReader(System.in));
   String sd=br.readLine();
   if (sd.equals("1"))
   {
   pop();
   printf1();
   }
   
   else if (sd.equals("2"))
   {
   push(99);
   printf1();
   } 
   
  } catch (NumberFormatException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
       
    }
   
   
    public void push(int number) // push()는 Stack 의 맨 위에 쌓아놓을 수 있다  >> data 배열에 숫자를 넣음
    {
        data[++top] = number; //++top 연산을 통해서 top 은 push 함수를 호출할 때마다 하나씩 위로 올라가서 Stack 의 맨 위를 언제나 가리키게 됨
                                         // 배열 이므로 제일 나중에 집어넣은 원소의 Index 를 보유

        many_items++; // Stack 에 저장된 원소의 갯수 1 증가
    }

   
    public int pop() // 맨 위에서만 빼낼 수 있다
 {
  many_items--; // Stack 에 저장된 원소의 갯수 1 감소
  return data[top--]; // 배열에서 맨위의 값을 반환하고 인덱스 를 1 감소시킴
 }
   
   

    public void printf1() // 배열 출력
    {
     for(int i=0;i<many_items;i++){
     System.out.print(data[i]+",");
  }
    }

     public static void main(String[] args)
     {
 new IntStack_A(5);
      }
}

------------------------------------------------------------------------------------------------------------------

 

4. Array 로 Queue 구현
------------------------------------------------------------------------------------------------------------------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class IntQueue_A {
 
    private int[] data;

    private int rear;   // Queue 맨위

    private int many_items; // 현재 Queue 에 몇 개의 원소가 있는지를 저장해 놓은 변수

    private int Queue_size; // Queue 의 전체 크기
   
    private BufferedReader br ;

public IntQueue_A(int size) // size : Queue 크기
    {
        data = new int[size];

        Queue_size = size;      

        rear = -1; // Queue 가 비어 있을 때

        many_items = 0;

     System.out.println("값을 입력하세요 :");
     try {
      br = new BufferedReader(new InputStreamReader(System.in));
      push(Integer.parseInt(br.readLine()));
      br = new BufferedReader(new InputStreamReader(System.in));
      push(Integer.parseInt(br.readLine()));
      br = new BufferedReader(new InputStreamReader(System.in));
      push(Integer.parseInt(br.readLine()));
      br = new BufferedReader(new InputStreamReader(System.in));
      push(Integer.parseInt(br.readLine()));

   printf1();   
   System.out.println("");
   System.out.println("1.삭제(POP)  2.삽입(PUSH)");
   br = new BufferedReader(new InputStreamReader(System.in));
   String sd=br.readLine();
   if (sd.equals("1"))
   {
   pop();
   printf1();
   }
   
   else if (sd.equals("2"))
   {
   push(99);
   printf1();
   }  
   
  } catch (NumberFormatException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }       
    }
       
    public void push(int number) //  data 배열에 숫자를 넣음
    {
        data[++rear] = number; //

        many_items++; // Queue 에 저장된 원소의 갯수 1 증가
    }
   
    public void pop() // 맨 위에서만 빼낼 수 있다
 {

  for (int i=0;i<many_items;i++)
  {
   data[i] = data[i+1];
  }

  many_items--; // Queue 에 저장된 원소의 갯수 1 감소
 }

    public void printf1() // 배열 출력
    {
     for(int i=0;i<many_items;i++){
     System.out.print(data[i]+",");
  }
    }

 public static void main(String[] args) {
  new IntQueue_A(5);
 }
}
------------------------------------------------------------------------------------------------------------------

 

5. LinkedList 로 Stack 구현
------------------------------------------------------------------------------------------------------------------
public class LinkedListStack {
 public static void main(String[] args) {
  LinkedList list = new LinkedList(new Node(50));
  list.append(new Node(20));
  list.append(new Node(30));
  print(list.getHeader());
  list.remove_back();
  print(list.getHeader());
  list.append(new Node(10));
  print(list.getHeader());
  list.append(new Node(60));
  print(list.getHeader());
  list.remove_back();
  print(list.getHeader());
  list.remove_back();
 }

 private static void print(Node header) {
  Node list = header;
  while (list != null) {
   System.out.print(list.value + " -> ");
   list = list.next;
  }
  System.out.println();
 }
}
------------------------------------------------------------------------------------------------------------------

 

6. LinkedList 로 Queue 구현
------------------------------------------------------------------------------------------------------------------
public class LinkedListQueue {
 public static void main(String[] args) {
  LinkedList list = new LinkedList(new Node(50));
  list.append(new Node(20));
  list.append(new Node(30));
  print(list.getHeader());
  list.append(new Node(10));
  print(list.getHeader());
  list.append(new Node(60));
  print(list.getHeader());
  list.remove_front();
  print(list.getHeader());
 }

 private static void print(Node header) {
  Node list = header;
  while (list != null) {
   System.out.print(list.value + " -> ");
   list = list.next;
  }
  System.out.println();
 }
}

'자료구조' 카테고리의 다른 글

자료구조(해싱)  (0) 2009.11.06
자료구조 ( Array와 Linked List)-  (0) 2009.11.06
Posted by 인천총각
|


◆◆ Array 와 Linkedlist : 같은 타입의 여러가지 요소 (집합) 를 저장

◆ 1. Array

  ㉠ 정의

      index 와 index에 대응하는 데이터들로 이루어진 자료 구조를 나타낸다.

      즉, 동일한 자료형이고 메모리상에 연속적으로 놓인 데이터를 일괄적으로 처리하기 위해서

      만든 하나의 집합 형식으로 묶어놓은 자료 구조이다.

  ㉡ 특징

       메모리 할당이 연속적이어서 인덱스 사용시 검색이 빠르다.

       메모리 관리면에서 공간의 낭비가 심하다.

       자료의 삽입및 삭제가 어렵다.

 

◆ 2. Linkedlist

  ㉠ 정의

      연결 리스트, 링크드 리스트(linked list)는 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식으로 데이터를 저장하
      는 자료 구조이다.

      이름에서 말하듯이 데이터를 담고 있는 노드들이 연결되어 있는데, 노드의 포인터가 다음이나 이전의 노드와의 연결을 담당하게
      된다.

  ㉡ 특징

      메모리 할당이 비연속적이며, 크기가 동적이므로 낭비가 없다.

      보통 element 와 element 를 가로 질러서 조건에 맞을 때까지 순차 검색하므로 검색이 느리다.

      자료의 삽입및 삭제가 쉽다.     

  ㉢ 종류

      가. 단순 연결 리스트 : 각 노드에 자료 공간과 한 개의 포인터 공간이 있고, 각 노드의 포인터는 다음 노드를 가르킴

      나. 이중 연결 리스트 : 단순 연결 리스트와 비슷하지만, 포인터 공간이 두 개가 있고 각각의 포인터는 앞의 노드와 뒤의 노드를 가
                                     리킴

      다. 원형 연결 리스트 : 일반적인 연결 리스트에 마지막 노드와 처음 노드를 연결시켜 원형으로 만든 구조

 

◆◆ 3. Arrays and linked lists 중 어떤 것을 사용할지 결정하기 (중요!!)

   ㉠ 사이즈 면에서....

      Arrays 은 사용자의 필요에 따라 1차 혹은 다차 원으로 구현할수 있다.

      linked lists 는 태생적으로 1차원이며, 각각의 요소(element)들은 이전 요소와 다음 요소의 포인터를 가지고 있다.

 

   ㉡ 할당 면에서....

      Arrays는 만들어질때부터 사이즈가 정적으로 정의 된다. 게다가 Arrays에서 메모리 할당은 인접하며 끊어지지 않는다.

      >>>> Contiguous Memory Allocation - 연속 메모리할당 (프로세스들에게 연속된 메모리 공간을 할당해 주는 것)

      그러므로 Arrays는 디자인할 당시에 요소(element)의 최대 숫자를 알고있을 때 전형적으로 사용된다.

      이러한 접근방식으로 구현한 배열 단점은 커다란 배열은 아마도 사용되지 않는 큰 메모리가 필요로 한다는 것이다.

      특히나 이렇게 요소의 최대값으로 디자인된 배열은 종종 그들의 용량에 비해 턱없이 작게 저장되기도 한다.

      그리고 오래된 os 를 가진 초소형 장치들과 같은 경우에 메모리 제약이 당신이 사용할수 있는 배열의 크기를 제한할 수도 있다.

      반면에, linked lists 는 보통 동적이다. 실시간으로 필요할 때 마다 줄이거나 키울 수 있다.

      이러한 특징들로 인해서 linked lists 는 요소의 수를 몰랐을 때 좀더 효과적으로 사용될 수 있다.

      뿐만아니라 메모리가 요소요소에 의해 할당되므로, 비연속적이다.

      이런 불확실성을 다루는데서 오는 단점은 linked lists에서 추가하거나 지울때에 미리 할당된 배열된 요소들의 값을 정의할때 보다 
      좀더 부하가 있다 라는 것이다.

      그러나 linked lists에 얼마나 많은 메모리가 할당될 것이냐에 대한 유일한 제한은 당신의 목적에 의해서 사용하는 힙메모리의 크기
      에 의해서 결정되어진다.


   ㉢ 요소를 접근하는 방식에 있어서....

      Arrays 안에 있는 요소들은 그들의 인덱스를 통해서 접근할 수 있다. 그러므로 데이터 접근은 찾을 요소를 알면 빠르고 쉽다.

      만약 요소의 인덱스를 모르고 어떤 키값에 의해서 정렬되어있을 경우에 보다 효율적으로 특정 요소를 찾아낼 수 있다.

      이러한 알고리듬은 특정 요소가 위치하는 비교 의 최소값만을 허락하며,

      Arrays를 병합하거나 정렬하는 효율적이고 안정적인 몇가지 알고리듬들이 존재한다.

      그러나 Arrays는 요소의 순서가 쉽게 변할 때 비효율적이다. 요소가 자주 지워지거나 삽입되는 배열을 관리할 경우에 배열의 모든
      요소를 옮겨나를 필요가 있다.

      반면에, linked lists는 보통 요소와 요소를 가로 질러서 조건에 맞을 때까지 검색한다.

      왜냐하면 linked lists 에 대한 메모리는 연속적이라고 보장할 수 없기 때문이다.

      이러한 검색방법은 (인덱스와 같은 다른 데이터 구조체를 포함하지않는) 리스트를 검색하는 유일한 방식이다.

      비연속 메모리의 윗쪽부분은 리스트를 다시 정의하는 것으로, 단순히 링크를 조정하는 것을 포함한다.

      요소의 삽입과 삭제는 포인터 수정을 필요로 하고 실제적인 데이터의 전송은 전혀 필요로 하지 않는다.


   ㉣ 규칙들을 깨는 것

      거의 모든 언어에서 두가지 방식을 모두 지원을 한다.

      C에서 변수나 객체를 가르키는 포인터는 만약 그 포인터가 할당된 배열 안에서 첫번째 요소를 가르킬 때 배열처럼 사용할 수 있다.

      이렇게 포인터를 배열처럼 사용할 때 이 포인터의 크기조절이 필요하면,

      realloc() 라는 펑션이 메모리의 새로운 블럭을 할당하고 새로운 위치로 존재하는 모든 요소를 옮긴다.

      이러한 기법은 연속적인 메모리 할당 과 요소 인덱싱을 유지하는 가운데 배열의 동적인 리사이징을 가능하게 한다.

      Java 에서는 제공되는 linked-list class 가 인덱싱 되는 기법 뿐만아니라 top, next, previous, etc. 과 같은 표준 리스트 메서드를
      모두 지원한다.

      indexOf(), get(), and set() 과 같은 메서드들은 리스트의 요소가 흡사 배열과 같이 엑세스 되도록 도와준다.

      게다가 Java는 리스트 클래스의 향상된 리사이즈가능한 배열을 나타내는 "ArrayList class " 를 제공한다.

      이 두가지 클래스 모두 그들의 리스트 표현방식에서 실제 배열로 변환되는 메서드를 지원한다.

      프로그래밍 언어가 갈수록 진화되고있고 두가지 구조체의 구분이 점점 모호해지고 있다.

      하지만 어디서 이러한 구조체들이 고안되었는지 그리고 새로운 클래스안에서 어떻게 쓰여지고 있는지 기억하는것은 항상 중요하
      다.

      이러한 새로운 개선들은 프로그래머에게 자세한 부분을 숨기곤 함에도 불구하고, 요구되는 컴퓨터적인 부하 와 자원들은 변하지
      않는다.


   ㉤ 결정내리기....

      만약 당신의 데이터가 다차원적인 구조체로 표현이 되어지거나, 요소들의 숫자를 미리 알게 되거나, 일관된 성질을 가지고 있다면
      array 가 제일 좋다.

      만약 당신의 데이터가 1차원으로 쉽게 표현이 된다거나, 요소의 숫자들을 알지 못한다거나, 목적상 데이터가 자주 변한다고 생각
      이 되어질거라 예상될 때라면  linked lists 가 좀더 효율적이다.

      만약 당신의 데이터가 자주 검색되거나 접근되고 수정이 잦질 않다면 array 가 당신이 기대하는 운영에서 최소의 부하를 제공한다.

      만약 당신이 정기적으로 요소를 추가하거나 제거할때, 특별히 정렬된 순서를 그대로 유지할 필요가 있을 때 linked lists를 사용하
      는 것이 낫다.

      결국엔 당신의 데이터 와 당신의 운영면에서의 필요가 당신의 목적에 어떤 구조체가 최선인지 결정할 것이다.

원문:
http://articles.techrepublic.com.com/5100-10878_11-1050183.html

'자료구조' 카테고리의 다른 글

자료구조(해싱)  (0) 2009.11.06
자료구조(Stack 과 Queue)  (0) 2009.11.06
Posted by 인천총각
|