반응형




프로그래밍 초짜가 이거 짜냐고 마음에 병들었다.. ㅋㅋㅋ 스트레스 많이 받아서..

밑에 이진탐색트리는 삽입/삭제/순환,반복순회(전위,중위,후위)/파일로부터 이진탐색트리 불러오기 파일로 저장하기 다 된다. 참고로 레포트 사이트에서 몇천원 주고 구해도 요렇게 기능 많은 소스는 못 받을 소스다.. 물론 내가 코딩한게 약간 이상한 부분도 많지만...

혹시나 나 처럼 자료구조 레포트로 이진탐색트리 코딩해야되는 사람들은 꼭~ 검색 밑에 소스가 걸리기를 바란다... 내가 허접하게 주석도 달았다. ㅋㅋ 필요하면 파일도 같이 다운 받아기를...

/*
-File name : binarytree.c
-Compiler : Microsoft Visual C++ (ANSI C)
 다른 컴파일러에서는 오류가 발생할 수도 있음.
*/

/*********************************
 * 자료구조 레포트               *
 * 이름

 * 학번 :

 * 학년 :

 * 학과 : 컴퓨터과학전공         *
 * 작성일 : 05. 4. 7 ~ 05. 4. 20 *
 *********************************/

/******************************************************************
 * [*]프로그램에 사용된 주요 표준 함수 설명                       *
 *   <> (void *)malloc(size_t n_size)                             *
 *     -n_size 만큼 메모리를 할당 일반형 포인터로 주소 반환한다.  *
 *      메모리 할당 실패시에는 NULL값을 반환한다.                 *
 *   <> int fscanf(FILE *s, const char *format, ...)              *
 *     -*s로부터 정보를 받아 오며 스티림의 끝에 왔을 때는 EOF를   *
 *      반환한다. EOF(End of file)                                *
 *   <> int fprintf(FILE *s, const char *format, ...)             *
 *     -fscanf와는 반대로 *s(스트림)으로 *format을 입력한다.      *
 *   <> void exit(int status)                                     *
 *     -프로그램을 정상 종료 시킨다.                              *
 ******************************************************************/

/*
아래 '#'이 붙은 것들은 컴파일러 실행전 전처리가 먼저 읽어들여
프로그램에 삽입 또는 변환(기호상수)을 하면 최종적으로 컴파일러 처리하고 링커가
실행파일을 만든다.
*/
#include <stdio.h>
#include <stdlib.h> //malloc() 동적 메모리 할당 함수를 사용하기 위해 include.
#define MAX_SIZE 100
/*프로그램 곳곳에 퍼져 있는 최대 값을 기호상수(매크로정의)로 정의하므로서
한번에 값을 수정할 수 있어 혼란를 줄이고 어떤 의미인지 쉽게 의미 전달.
그러나 MAX_SIZE 100이 int형인지 정확히 정의할 수는 없다.*/

/* structure(구조체)는 java, c++의 class 개념과 매우 유사하며 사용법 역시 비슷하다.
java, c++ 에서는 new연산자로 구조체와 비슷한 개념의 class의 객체의 메모리를 할당한다면
c에서도 이와 유사하게 malloc()로 해당 구조체의 실체 메모리 공간을 할당할 수도 있다.*/
typedef struct {
 int hakbun;
 char name[20];
 short int year; //정수 4 이상 입력은 대부분 없므으로 short형
 char department[25];
} element;

struct tree {
 element data;
 struct tree *left_child, *right_child;
};

//가독성 또는 사용의 편리성을 위해 형정의
typedef struct tree node, *tree_pointer;

//tree_pointer형의 주소를 최대 MAX_SIZE만큼 저장하는 배열
tree_pointer queue[MAX_SIZE];
tree_pointer stack[MAX_SIZE];

int top = -1; //stack pointer -1로 초기

tree_pointer search_parent(tree_pointer tree, element data) {
 tree_pointer parent;
 //입력받은 학번을 트리 학번과 비교 삽입될 위치를 찾고 해당 위치의 부모노드 반환.
 while(tree) {
  //3가지의 경우가 있다. 데이터가 큰경우, 작은 경우, 예외.
  if(tree->data.hakbun > data.hakbun ) {
   parent = tree;
   //반복문을 돌면서 tree에 NULL값이 들어감으로 parent에 먼저 값을 저장해 놓는다.
   tree=tree->left_child;
  }
  else if(tree->data.hakbun < data.hakbun) {
   parent = tree;
   tree=tree->right_child;
  }
  else {
   printf("이미 존재하는 학번입니다.\n");
   exit(1);
  }
 }
 return parent;
}

void add_node(tree_pointer *tree, element data) {
 tree_pointer ptr, parent;

 /*아래 malloc()에서 할당되는 메모리크기는 node구조체에
 있는 각각의 변수형들의 byte 합과 동일하다.*/
 if((ptr = (tree_pointer)malloc(sizeof(node)))==NULL) {
  //ptr에 NULL이 들어가는 경우는 메모리 Full 또는 기타 예외상황
  fprintf(stderr, "동적메모리 할당 실패!!\n");
  /* stdout(모니터), stdin(키보드) 스트림과 마찬가지로 stderr도 기본 에러출력
  스트림이며 특이한 것은 버퍼를 사용하지 않고 바로 모니터에 에러 메세지를
  출력한다.*/
  exit(1);
 }

 ptr->data=data;
 ptr->left_child = ptr->right_child = NULL;
 /*포인터 변수를 NULL로 초기화 시키지 않으면 쓰레기 값으로 인해
 segment fault를 발생시킬 수 있다.*/
 
 if(*tree) {
  //printf("Tree pointer is not null\n");
  parent = search_parent(*tree, data);
  //search_parent()는 입력 받은 데이터가 삽입될 부모노드를 찾아 준다.

  //입력된 학번과 search_parent()의해 구해진 부모 노드의 학번을 비교
  if(parent->data.hakbun > data.hakbun)
   parent->left_child = ptr; //입력된 학번이 작으면 부모의 왼쪽 sub트리.
  else if(parent->data.hakbun < data.hakbun)
   parent->right_child = ptr; //입력된 학번이 크면 부모의 오른쪽 sub트리.
  else
   printf("이미 존재하는 학번입니다.\n");
 }
 else {
  //printf("Tree pointer is null\n");
  *tree=ptr;
  /*이중포인터에 *(역참조)연산자를 붙였음으로 값으로 갖고 있는 주소를
  malloc()에서 반환 동적메모리 주소로 넣는다.*/
 }
}

element delete_max(tree_pointer* ptr)
{
 element max;
 tree_pointer temp;

 /*양쪽 자식을 모두 갖고 있는 경우 삭제 방법은 왼쪽 자식 sub트리 중 가장 큰 값을 삭제할
 위치에 놓는 것이다. 그러므로 링크를 변경하는 힘든 작업은 없다.
 다만 삭제될 왼쪽 sub트리 중 가장 큰 값의 노드의 왼쪽 자식 링크만 변경한다.*/

 if ((*ptr)->right_child == NULL) {
  max = (*ptr)->data; //삭제될 트리의 왼쪽 sub트리 중 값이 가장 노드를 max저장
  temp = *ptr; //sub트리 가자어 오늘 단말 노드를 temp에 저장
  *ptr = (*ptr)->left_child;
  /* *ptr은 삭제될 트리의 왼쪽 sub트리 중 가장 큰 값을 갖고 있는 트리이며
  자신의 원래 값은 max에 저장해 반환시키고 자신의 위치에는 자신의
  왼쪽 자식을 넣는다.*/

  free(temp); //연결이 끊어진 동적메모리를 해제시켜 메모리 낭비를 없앤다.
  return max; //max 노드 값을 리턴해 삭제할 노드에 값을 바꿔준다.
 } else {
 //오른쪽 자식이 있을 경우 delete_max()에 오른쪽 자식을 넣고 재호출한다.
  return delete_max(&(*ptr)->right_child);
 // &(*ptr)의 의미는 이중포인터 값 주소를 가리키는 주소를 뜻한다.
 }
}

void delete_node(tree_pointer* ptr, int value)
{

 if (*ptr) {
  //삭제될 학번과 트리의 학번을 비교 작으면 왼쪽 sub트리로 함수 재호출
  if (value < (*ptr)->data.hakbun) {
   delete_node(&(*ptr)->left_child, value);
  //삭제될 학번과 트리의 학번을 비교 크면 오른쪽쪽 sub트리로 함수 재호출
  } else if (value > (*ptr)->data.hakbun) {
   delete_node(&(*ptr)->right_child, value);
  }
  //트리 노드의 좌/우 자식이 없으면 *ptr을 NULL 넣어 삭제된다.
  else if ((*ptr)->left_child == NULL && (*ptr)->right_child == NULL)
   *ptr = NULL;
  //트리 노드의 왼쪽 자식이 없으면 *ptr에 오른쪽 자식을 넣어 자신은 삭제된다.
  else if ((*ptr)->left_child == NULL)
   *ptr = (*ptr)->right_child;
  //트리 노드의 오른쪽 자식이 없으면 *ptr에 왼쪽 자식을 넣어 자신은 삭제된다.
  else if ((*ptr)->right_child == NULL)
   *ptr = (*ptr)->left_child;
  else { // 트리에 좌/우 자식이 모두 붙어 있는 경우.
   (*ptr)->data = delete_max(&(*ptr)->left_child);
   //삭제될 위치에 왼쪽 sub트리 중에 가장 큰 값으로 바꾼다.
  }
 }
}

//~~~~~~~~~~~ I'm with you~~~~~~~~~~~ ^,.^;;;
//직접 Data를 입력 받는 함수
void input_data(tree_pointer *tree, element data) {

  printf("학번 : ");
  scanf("%d", &data.hakbun);
  printf("이름 : ");
  scanf("%s", &data.name);
  printf("학년 : ");
  scanf("%d", &data.year);
  printf("학과(전공) : ");
  scanf("%s", &data.department);

  add_node(&(*tree), data);

}

// data.txt로부터 저장된 내용을 불러오는 함수
void load_file(tree_pointer *tree, element data) {
 FILE *fp;
 int count=0;

 if((fp=fopen("data.txt", "r")) == NULL) {
  fprintf(stderr, "파일 불러오기 실패!!");
  exit(1);
 }

 printf("\n*******************************************************\n");
 printf("             파일로부터 불러온 학생 명단-\n");
 while(fscanf(fp, "%d", &data.hakbun) != EOF) {
  //위에도 적었지만 fscanf()는 파일에 끝에 도달하면 -1(EOF)를 반환한다.
  printf("-------------------------------------------------------\n");
  printf("* 학번 : %d", data.hakbun);
  fscanf(fp, "%s", &data.name);
  printf(", 이름 : %s", data.name);
  fscanf(fp, "%d", &data.year);
  printf(", 학년 : %d", data.year);
  fscanf(fp, "%s", &data.department);
  printf(", 전공 : %s\n", data.department);
  add_node(&(*tree), data);
  /* "&(*tree)"가 의미하는 것은 이중포인터에 *연산자를 하나 붙임으로서
  이중포인터가 갖고 있는 주소 값을 의하고 괄호 밖에 &연산자를 붙임으로서
  그 주소값을 가리키는 주소를 뜻한다. 즉 메인에서 정의된 tree포인터의 주소.*/
  count++; //행(레코드 또는 튜플)단위로 카운트를 증가시킨다.
 }
 printf("*******************************************************\n");
 printf("**data.txt로부터 [ %d ]명의 학생 정보를 로드했습니다.**\n", count);
 printf("*******************************************************\n");
 fclose(fp); //파일 스티림을 닫는다.
}

//이 프로그램에서 학생 정보 출력하는 모든 함수는 printStd()를 호출해서 사용한다.
void printStd(tree_pointer tree) {
  printf("\n학번 : %d (Primary key)\n", tree->data.hakbun);
  printf("----------\n");
  printf("이름 : %s\n", tree->data.name);
  printf("학년 : %d\n", tree->data.year);
  printf("학과(전공) : %s\n", tree->data.department);
}

void pre_order(tree_pointer tree) {
 if(tree) {
  printStd(tree);
  pre_order(tree->left_child); //스택에 쌓이면서 NULL이 나올 때까지 내려 간다.
  pre_order(tree->right_child);
  // Value→Left→Right
 }
}

void in_order(tree_pointer tree) {
 if(tree) {
  in_order(tree->left_child);
  printStd(tree);
  in_order(tree->right_child);
  // Left→Value→Right
 }
}

void post_order(tree_pointer tree) {
 if(tree) {
  post_order(tree->left_child);
  post_order(tree->right_child);
  printStd(tree);
  // Left→Right→Value
 }
}

void queue_full(int *rear) {
 if((*rear%MAX_SIZE) == 0)
  *rear = MAX_SIZE-1;
 //rear가 MAX_SIZE랑 똑같은 값이면 MAX_SIZE 보다 1 작은 수를 넣어준다.
 else
  *rear -= 1;
 //rear가 MAX_SIZE와 값이 틀리면 그냥 1만 감소시켜준다.

 fprintf(stderr, "메모리초과 rear %d로 리셋\n", *rear);
}

tree_pointer queue_empty(int *front) {
 fprintf(stderr,"\nfront : %d\n", *front);
 return queue[*front+1];
 //front와 rear가 같아지면 front를 1증시켜 리턴시켜준다.
}

//deleteq()는 front를 1증가 시켜 메모리에 한 노드의 저장된 주소를
tree_pointer deleteq(int *front, int rear) {
 if(*front == rear)
  return queue_empty(front); //오류 키를 반환
 queue[*front]=NULL;
 *front = (*front+1) % MAX_SIZE; //나머지 연산으로 환형을 만든다.
 //MAX_SIZE와 동일할 경우를 제외하고는 모두 (*front+1)값이 *front에 들어간다.
 return queue[*front];
}

//add queue
int addq(int front, int *rear, tree_pointer item) {
 *rear = (*rear+1) % MAX_SIZE;
 //MAX_SIZE와 동일할 경우를 제외하고는 모두 (*rear+1)값이 나온다.
 if(front == *rear) {
  queue_full(rear);
  return 0;
 }
 queue[*rear] = item;
 return 0;
}

//반복적 레벨 순서 트리 순회(환형큐 사용)
int level_order(tree_pointer ptr) {
 int front = 0, rear = 0;
 //front, rear를 모두 0으로 초기화시킨다.(데이타를 배열의 1번 부터 들어간다.)
 if(!ptr) return 0;
 //인자 ptr의 값이 비어 있으면 리턴시켜 호출한 함수로 돌아간다.
 addq(front, &rear, ptr);
 /*현재 노드를 큐메모리에 추가한다. rear의 주소 값을 매개변수 넣어주는 이유는 addq()에서
 증가된 rear의 값을 그대로 유지하기 위해서*/
 for(;;) {
  ptr = deleteq(&front, rear);
  //front값을 1증가 시켜 addq로 입력시킨 노드를 ptr에 넣는다.
 
  if(ptr) { //queue_empty()에서 NULL값을 반환할 때까지 반복.
   printf("\n");
   printStd(ptr); //현재에 ptr노드의 data 화면에 출력
   if(ptr->left_child)
    addq(front, &rear, ptr->left_child);
   if(ptr->right_child)
    addq(front, &rear, ptr->right_child);
  }
  else break;
 }
 printf("rear : %d\n", rear);
 return 0;
}

tree_pointer stack_empty(int *top) {
 fprintf(stderr, "\n스택포인터 %d에 위치!!\n", *top);
 return stack[*top];
}

int push(int *top, tree_pointer item)
{
 if(*top >= MAX_SIZE-1) {
  fprintf(stderr,"스택 메모리 꽉!!\n");
  return 0;
 }
 stack[++*top] = item;
 //++가 *top 앞에 있므로 1증가한 자리에 item이 들어간다.
 return 0;
}

tree_pointer pop(int *top) {
 if(*top == -1)
  return stack_empty(top);

 return stack[(*top)--]; //*top번째 있는 원소를 반환하고 *top값을 감소시킨다.
}

//반복적 전위
void iter_preorder(tree_pointer node) {
 for(;;) {
  /*for문의 반복 조건은 node에 값이 항상 들어 있고 후위식은
  한번 반복 수행 완료후 node의 값을 왼쪽 자식 node로 바꿔 준다.*/
  for(;node; node=node->left_child) {
   //우선 트리 왼쪽의 모든 노드를 스택에 다 넣어 준다.
   printStd(node);
   push(&top, node);//node를 스택에 넣고 top를 1 증가 시킨다.
  }
  node=pop(&top);//nodedp top가 가리키는 곳의 node를 넣고 top는 1 감소한다.
  if(!node) break;

  node=node->right_child;
  //위에 for문에서 왼쪽 노드를 넣어 둔 것들의 오른쪽 자식을 하나씩 넣어 반복한다.
 }
}

//반복적 중위
void iter_inorder(tree_pointer node) {
 for(;;) {
  for(;node; node=node->left_child)
   push(&top, node);
  node=pop(&top);
  if(!node) break;
  printStd(node);
  node=node->right_child;
 }
}

//반복적 후위
/*void iter_postorder(tree_pointer node) {
 // ㅡ,.ㅡ;; ~ Happy~ Happy~ Happy~
}*/

//이진트리를 순환 방식으로 복사합니다.
tree_pointer copy(tree_pointer original) {
 tree_pointer temp; //temp에 오리지널 트리가 저장되어 호출시킨 함수로 리턴.
 if(original) {
  if((temp = (tree_pointer)malloc(sizeof(node))) == NULL) {
   fprintf(stderr,"동적 메모리 할당 실패!!\n"); exit(1);
  }
  temp->left_child = copy(original->left_child);
  //순환적으로 original의 왼쪽 자식을 temp의 왼쪽 자식에 넣는다.
  temp->right_child = copy(original->right_child);
  //역시 함수의 순환(스택메모리)를 이용 오늘쪽 자식을 저장해 나간다.
  temp->data = original->data;
  return temp;
 }
 return NULL;
}

//원본과 복사본 비교 동일한 경우 1을 반환한다.
int equal(tree_pointer first, tree_pointer second) {
 return((!first && !second)|| // 둘 다 똑같이 값이 없을 경우 참이다.
  (first && second && (first->data.hakbun == second->data.hakbun)) &&
  //둘 다 값이 들어 있고 주키(primary key) 학번 값이 똑같아야 참이다.
  equal(first->left_child, second->left_child) &&
  //위에 내용을 재귀함수로 sub트리 까지 비교한다.
  equal(first->right_child, second->right_child));
 /*전체적인 내용은 이렇다.
 둘다 값이 없을 경우 또는(c, c++, java 등등 언어에서 or(||)연산은 앞에 조건이 맞으면
 뒤는 검사하지 않고 참으로 판단한다. 그러므로 뒤에 and연산은 아무런 연산도 없다.)
 둘다 값이 존재 그리고(and(&&) 연산은 앞, 뒤 조건이 모두 참일 때 참이다.)
 두 개의 학번이 동일 그리고 sub트리까지 모두 같으면 참(1)을 반환한다.*/
 //c언어 에서는 0을 제외하고 모든 것을 참으로 판단한다. -1도 참이다.
}

void traversal(tree_pointer tree) {
 int sel;
 while(sel) {
 
  printf("\n***************************************\n");
  printf("* <*>순환 순회(재귀함수)              *\n");
  printf("*  (1). 전위, (2). 중위, (3). 후위    *\n");
  printf("* <*>반복 순회(Loop제어문)            *\n");
  printf("*  (4). 전위, (5). 중위, (6). 후위    *\n");
  printf("*  (7). 레벨순회(환형큐),(0). Exit    *\n");
  printf("***************************************\n");
 while(1) {
   printf("번호 선택 : ");
   rewind(stdin);
   scanf("%d", &sel);
   if(0 > sel || sel > 7)
    printf("\n\n**장난하냐? 0~7 사이만 누르라고 몇번을 말해!!**\n\n");
   else break;
  }

  switch(sel) {
  case 1 :
   printf("\n전위순회 :\n");
   pre_order(tree);
   printf("\n**전위순회(Value→Left→Right)완료!**\n");
   break;
 
  case 2 :
   printf("\n중위순회 : \n");
   in_order(tree);
   printf("\n**중위순회(Left→Value→Right)완료!**\n");
   break;
 
  case 3 :
   printf("\n후위순회 : \n");
   post_order(tree);
   printf("\n**후위순회(Left→Right→Value)완료!**\n");
   break;
 
  case 4 :
   printf("\n반복적 전위순회 : \n");
   iter_preorder(tree);
   printf("\n**반복적 전위순회완료!**\n\n");
   break;
 
  case 5 :
   printf("\n반복적 중위순회 : \n");
   iter_inorder(tree);
   printf("\n**반복적 중위순회완료!**\n\n");
   break;
 
  case  6 :
   printf("\n반복적 후위순회 : \n");
   //iter_postorder(tree);
   printf("요건 어려워.. 손으로 그려 봐요\n");
   printf("\n**반복적 후위순회완료!**\n\n");
   break;
 
  case 7 :
   printf("\n레벨순서순회 : \n");
   level_order(tree);
   printf("\n**레벨순서순회(hight level→low level)완료!**\n\n");
   break;
  default :
   break;
  }
 }
 printf("\n");
}

//전위순회 순으로 fp파일 스트림에 tree포인터의 내용을 쓴다.
void start_save(tree_pointer tree, FILE *fp) {
 if(tree) {
  fprintf(fp, "%d ", tree->data.hakbun);
  //여기서 fp를 stdout(모니터)스트림으로 변경하면 일반 printf()와 동일한 효과.
  fprintf(fp, "%s ", tree->data.name);
  fprintf(fp, "%d ", tree->data.year);
  fprintf(fp, "%s\n", tree->data.department);
  start_save(tree->left_child, fp);
  start_save(tree->right_child, fp);
 }
}

void save_data(tree_pointer tree) {
 FILE *fp;

 if((fp=fopen("out_data.txt","w")) == NULL) {
  fprintf(stderr, "파일 열기 실패!!");
  exit(1);}

 printf("\n\n**파일은 전위순회 순으로 저장됩니다**\n");
 start_save(tree, fp);//함수의 순환방법으로 파일 저장.
 printf("out_data.txt 파일에 저장 완료!!\n");
 printf("Have a nice day~\n");
 fclose(fp);//열린 파일 스트림을 닫아 준다.
}

int main() {

 element data;
 tree_pointer tree = NULL, clone=NULL;
 /*밑에서 포인터 tree를 함수 매겨변수로 넣을 때 트리가 갖고 있는 주소 값을
 넘기는 것이 아니고 주소값을 갖고 있는 메모리의 주소를 넘겨주는 이유는
 초기 값이 NULL임으로 값을 넘겨주면 "Segment fault"를 발생시킨다.
 즉, 따른 애가 사용하고 있는 메모리를 침범한다. 이 실수는 문법의 문제가 아니다 그래서
 상황에 따라서는 컴파일러가 못 찾을 때있다. o/s(window,unix,linux)에서는 세그먼트펄트를
 감지해서 에러메세지 출력하고 프로세스를 강제 종료시키거나 어떤 조치에 들어간다. */

 //tree_pinter형은 sturct tree *동일.
 char sel; //메뉴 선택 문자를 받기 위해 선언된 변수.
 int value; //노드 삭제시 학번을 입력 받기 위해 선언된 변수.

 printf("*♡*♥*♡*♥*♡*♥*♡*♥*♡*♥*♡*♥*♡*♥*\n");
 printf("* [평 택 대 학 교]                        *\n");

 printf("* ------ ------- -------- ------------    *\n");
 printf("* B i n a r y S e a r c h               *\n");
 printf("*    ttttttt   rrrrrr    eeeee   eeeee    *\n");
 printf("*      tt      rr   rr   ee      ee       *\n");
 printf("*      tt      rrrrr     eeeee   eeeee    *\n");
 printf("*      tt      rr  rr    ee      ee       *\n");
 printf("*      tt      rr   rr   eeeee   eeeee    *\n");
 printf("*     (Field : 학번, 이름, 학년, 학과)    *\n");
 printf("*******************************************\n");
 printf("\n\n*복사, 순회, 삭제는 Data 입력 또는 로드후 사용*\n");
 
 while(sel != 'x') {//sel입력된 문자가 'x'가 아닌 경우 조건은 참.
 
  printf("입력(i)/파일로드(f)/복사(c)/순회(t)/삭제(d)/종료(x) : ");
 
  rewind(stdin); //fflush()함수와 동일한 역할을 하며 스트림 지시자를 초기화
  scanf("%c", &sel);

  switch(sel) {
  case 'i' :
   input_data(&tree, data); //데이타를 직접 입력받기 위한 함수 호출.
   break;
  case 'f' :
   load_file(&tree, data); //외부 파일을 불러오는 함수 호출.
   break;
  case 'c' :
   clone=copy(tree); //tree를 복사해 결과 주소를 clone 변수에 넣는다.
   if(equal(tree,clone)) printf("\n\n**트리 복사 성공!!**\n");
   else {printf("\n\n복사 실패!!\n"); break;}
   printf("\n\n**복사된 트리 순회해 보기**\n");
   traversal(clone); // 복사된 트리를 순회시켜 본다
   free(clone); //복사된 트리에 할당된 메모리는 바로 clear 시켜준다.
   printf("***복사된 트리 clone은 메모리 해제되었습니다***\n\n");
   break;
  case 'd' :
   printf("사라져 버리길 원하는 학생 학번 : ");
   scanf("%d", &value);
   delete_node(&tree, value); //삭제될 트리와, 대상 학번을 매겨변수 넣고 호출.
   break;
  case 't' :
   traversal(tree); //트리의 순회만을 모아 놓은 함수 호출.
   break;
  case 'x' :
   break;
  default :
   printf("\n\n**\'i\', \'f\', \'c\', \'t\', \'d\', \'x\' 한가지 골라 눌러요!**\n\n");
   break;
  }
 }

 for(;tree!=NULL;) { //저장 질문은 포인터 tree에 뭔가 들어 있을 때만 질문한다.
  printf("\n메모리에 적재된 트리 저장하고 종료할까요?(y or n) : ");
  rewind(stdin);
  scanf("%c", &sel);
  if(sel == 'y')
  { save_data(tree); break; }
  else if(sel == 'n') break;
  else { printf("\n\n\'y\' 또는 \'n\'만 입력!!\n"); continue; }
 }

 if(tree != NULL)
  free(tree); /*tree의 사용이 끝났으므로 할당된 메모리를 clear 시킨다.
     그맇지만 free()로 clear 시키지 않아도 프로그램 종료시에는
                 O/S에서 할당된 메모리를 자동으로 clear 시킨다.*/
 printf("\n\n*♡*♥*♡*♥*♡*♥*♡*♥*♡*♥*♡*♥*♡*♥*♡*\n");
 printf("* [평 택 대 학 교]                           *\n");
 printf("* ------ ------- -------- ------------       *\n");
 printf("*    B      Y   Y    EEEE                    *\n");
 printf("*    BBB     Y Y    E    E                   *\n");
 printf("*    B  B     Y     EEEEEE  ~   ~   ~  ~   ~ *\n");
 printf("*    B  B    Y      E         ~   ~   ~  ~   *\n");
 printf("*    BBB    Y        EEEE                    *\n");
 printf("*                                            *\n");
 printf("* ♬♪You can get it if you really want♬♪  *\n");
 printf("*   ♬♪But you must try, try and try~♬♪   *\n");
 printf("*       ♬♪you'll succeed at last♬♪       *\n");
 printf("**********************************************\n");

 return 0;

}

// End of code

반응형
Posted by Real_G