2024년 7월 3일 수요일

자료구조 3강 추상 자료형, 연결리스트 정리, 소스 코드

 추상 자료형(ADT, Abstract Data Type)

ADT란?

지갑을 ADT로 정리하면?

코드 구현

typedef struct _wallet
{
  int coin100Num; // 100원짜리 동전의 수
  int bill5000Num; // 5,000원짜리 지폐의 수  
}

int TakeOutMoney(Wallet * pw, int coinNum, int billNum); // 돈을 꺼내는 연산
void PutMoney(Wallet * pw, int coinNum, int billNum); // 돈을 넣는 연산

구체적인 기능의 완성과정을 언급하지 않고, 순수하게 기능이 무엇인지를 나열한 것을 가리켜 '추상 자료형' 또는 간단히 ADT라 한다.


리스트의 이해

리스트는 곧 연결리스트인가? X

리스트는 배열 기반의 순차리스트와 동적 할당 기반의 연결리스트로 나뉜다.

리스트 자료구조는 데이터를 나란히 저장하고 중복된 데이터의 저장을 막지 않는다.

리스트 자료구조의 ADT

void ListInit(List* plist)

: 초기화할 리스트의 주소 값을 인자로 저장한다.

: 리스트 생성 후 제일 먼저 호출되어야 하는 함수이다.

 

void LInsert(List* plist, LData data)

: 리스트에 데이터를 저장한다. 매개변수 data에 전달된 값을 저장한다. 

 

void LFirst(List* plist, LData pdata)

: 첫 번째 데이터가 pdata가 가리키는 메모리에 저장된다.

: 데이터의 참조를 위한 초기화가 진행된다.

: 참조 성공 시 TRUE(1), 실패 시 FALSE(0) 반환

 

void LNext(List* plist, LData pdata)

: 참조된 데이터의 다음 데이터가 pdata가 가리키는 메모리에 저장된다.

: 순차적인 참조를 위해서 반복 호출이 가능하다.

: 참조를 새로 시작하려면 먼저 LFirst 함수를 호출해야 한다.

: 참조 성공 시 TRUE(1), 실패 시 FALSE(0) 반환

 

LData LRemove(List* plist)

: LFirst 또는 LNext 함수의 마지막 반환 데이터를 삭제한다.

: 삭제된 데이터는 반환된다.

: 마지막 반환 데이터를 삭제하므로 연이은 반복 호출은 허용하지 않는다.

 

int LCount(List* plist)

: 리스트에 저장되어 있는 데이터의 수를 반환한다.



리스트의 ADT를 기반으로 정의된 main 함수

#include <stdio.h>
#include "ArrayList.h"

int main(void)
{
    //1. 리스트를 생성 및 초기화 한 다음, 정수 1부터 9까지 리스트에 저장한다.
    List list;
    int data;
    int sum = 0;
    ListInit(&list);
    
    for(int i=1; i<10; i++)
        LInsert(&list, i);
    
    printf("현재 데이터의 수: %d \n", LCount(&list));
    
    if(LFirst(&list, &data))
    {
        printf("%d ", data);
        
        while(LNext(&list, &data))
        {
            printf("%d ", data);
        }
    }
    printf("\n\n");
    
    //2. 리스트에 저장된 값을 순차적으로 참조하여 그 합을 계산하여 출력한다.
    if(LFirst(&list, &data))
    {
        sum = sum + data;
        
        while(LNext(&list, &data))
        {
            sum = sum + data;
        }
        
        printf("데이터의 총 합: %d \n\n", sum);
    }
        
    //3. 리스트에 저장된 값들 중 2의 배수와 3의 배수에 해당하는 값을 모두 삭제한다.
    if(LFirst(&list, &data))
    {
        if(data%2 == 0 || data%3 == 0)
            LRemove(&list);
        
        while(LNext(&list, &data))
        {
            if(data%2 == 0 || data%3 == 0)
                LRemove(&list);
        }
    }
    
    //4. 마지막으로 리스트에 저장된 데이터를 순서대로 출력한다.
    printf("현재 데이터의 수: %d \n", LCount(&list));
    
    if(LFirst(&list, &data))
    {
        printf("%d ", data);
        
        while(LNext(&list, &data))
        {
            printf("%d ", data);
        }
    }
    printf("\n\n");
    return 0;
}


배열 기반의 리스트인 ArrayList 헤더파일

// ArrayList.h

#ifndef __ARRAY_LIST_H__
#define __ARRAY_LIST_H__

#define TRUE        1
#define FALSE       0

#define LIST_LEN    100
typedef int LData;

typedef struct __ArrayList
{
    LData arr[LIST_LEN];
    int numOfData;
    int curPosition;
}  ArrayList;

typedef ArrayList List;

void ListInit(List * plist);
void LInsert(List * plist, LData data);

int LFirst(List * plist, LData * pdata);
int LNext(List * plist, LData * pdata);

LData LRemove(List * plist);
int LCount(List * plist);

#endif

구현 파일

// ArrayList.c

#include <stdio.h>
#include "ArrayList.h"

void ListInit(List * plist)
{
    (plist->numOfData) = 0;
    (plist->curPosition) = -1;
}

void LInsert(List * plist, LData data)
{
    if(plist->numOfData >= LIST_LEN)
    {
        puts("저장이 불가능합니다.");
        return;
    }

    plist->arr[plist->numOfData] = data;
    (plist-<numOfData)++;
}

inf LFirst(List * plist, LData * pdata)
{
    if(plist->numOfData == 0)
        return FALSE;

    (plist->curPosition) = 0;
    *pdata - plist->arr[0];
    return TRUE;
}

int LNext(List * plist, LData * pdata)
{
    if(plist->curPosition >= (plist->numOfData)-1)
        return FALSE;

    (plist->curPosition)++;
    *pdata = plist->arr[plist->curPosition];
    return TRUE;
}

LData LRemove(List * plist)
{
    int rpos = plist->curPosition;
    int num = plist->numOfData;
    int i;
    LData rdata = plist->arr[rpos];

    for(i=rpos; i<num-i; i++)
        plist->arr[i] = plist->arr[i+1];

    (plist->numOfData)--;
    (plist->curPosition)--;
    return rdata;
}

int LCount(List * plist)
{
    return plist->numOfData;
}

구조체 변수의 주소 값을 저장하기 위해 다음 구조체 함수들을 선언 및 정의

// Point.h

#ifndef __POINT_H_
#define __POINT_H_

typedef struct _point
{
    int xpos;
    int ypos;
} Point;

// Point 변수의 xpos, ypos 값 설정
void SetPointPos(Point * ppos, int xpos, int ypos);

// Point 변수의 xpos, ypos 정보 출력
void ShowPointPos(Point * ppos);

// 두 Point 변수의 비교
int PointComp(Point * pos1, Point * pos2);

#endif
// Point.c

#include <stdio.h>
#include "Point.h"

// Point 변수의 xpos, ypos 값 설정
void SetPointPos(Point * ppos, int xpos, int ypos)
{
    ppos->xpos = xpos;
    ppos->ypos = ypos;
}

// Point 변수의 xpos, ypos 정보 출력
void ShowPointPos(Point * ppos)
{
    printf("{%d, %d} \n", ppos->xpos, ppos->ypos);
}

// 두 Point 변수의 비교
int PointComp(Point * pos1, Point * pos2)
{
    if(pos1->xpos == pos2->xpos && pos1->ypos == pos2->ypos)
        return 0;
    else if(pos1->xpos == pos2->xpos)
        return 1;
    else if(pos1->ypos == pos2->ypos)
        return 2;
    else
        return -1;
}

위 Point 구조체를 기존 리스트 소스에 적용하려면

ArrayList.h에서 typedef int LData; 선언을 typedef Point * LData; 로 변경이 필요하다.

#include "Point.h" 헤더파일 선언도 당연히 필요

그리고 아래는 main 함수

main 함수 코드 구현



#include <stdio.h>
#include <stdlib.h>
#include "ArrayList.h"
#include "Point.h"

int main(void)
{
  List list;
  Point compPos; // 비교용 변수
  Point * ppos;

  ListInit(&list);

  // 4개의 데이터 저장
  ppos = (Point*)malloc(sizeof(Point));
  SetPointPos(ppos, 2, 1);
  LInsert(&list, ppos);

  ppos = (Point*)malloc(sizeof(Point));
  SetPointPos(ppos, 2, 2);
  LInsert(&list, ppos);
  
  ppos = (Point*)malloc(sizeof(Point));
  SetPointPos(ppos, 3, 1);
  LInsert(&list, ppos);

  ppos = (Point*)malloc(sizeof(Point));
  SetPointPos(ppos, 3, 2);
  LInsert(&list, ppos);

  // 저장된 데이터 출력
  printf("현재 데이터의 수: %d \n", LCount(&list));

  if(LFirst(&list, &ppos))
  {
    ShowPointPos(ppos);

    while(LNext(&list, &ppos))
        ShowPointPos(ppos);
  }

  printf("\n");

  // xpos가 2인 모든 데이터 삭제
  compPos.xpos=2;
  compPos.ypos=0;

  if(LFirst(&list, &ppos))
  {
    if(PointComp(ppos, &ppos))
    {
      if(PointComp(ppos, &compPos)==1)
      {
        ppos=LRemove(&list);
        free(ppos);
      }

      while(LNext(&list, &ppos))
      {
        if(PointComp(ppos, &comppos)==1)
        {
          ppos=LRemove(&list);
          free(ppos);
        }
      }
    }
  }

  printf("현재 데이터의 수: %d\n", LCount(&list));

  if(LFirst(&list, &ppos))
  {
    ShowPointPos(ppos);

    while(LNext(&list, *ppos))
      ShowPointPos(ppos);
  }
  printf("\n");

  return 0;
}


댓글 없음:

댓글 쓰기