[자료구조 - C언어] 자료구조 [11강-14강] 복습 및 정리
2022. 11. 9. 16:51ㆍCS/자료구조
728x90
//공부 기록용 포스팅입니다. 틀린 부분이 있을 경우 댓글로 알려주시면 감사합니다! 😎
자료구조 11강
- 배열
- 연결 리스트
- 노드(데이터 필드 + 링크 필드)들이 링크로 연결되어 있는 자료구조
- 첫 번째 노드를 저장하는 head 노드, 마지막 노드의 링크 필드는 NULL ~ 연결 리스트의 끝 표시
- 노드
-
typedef struct node{ char *data; //연결 리스트에 저장할 데이터 타입 지정 struct node * next; //다음 노드의 주소를 저장할 필드, 자기 참조형 구조체 }Node; Node *head = NULL; //연결 리스트의 첫 번째 노드의 주소를 저장할 포인터
- 자기 참조형 구조체: 자신과 동일한 구조체에 대한 포인터를 멤버로 가진다.
- struct node *next: struct node를 가리키고 있는 struct node 타입의 포인터 변수
- 자기 참조형 구조체: 자신과 동일한 구조체에 대한 포인터를 멤버로 가진다.
- 연결 리스트 사용 방법
-
//첫 노드 생성 Node *head = (Node *)malloc(sizeof(Node)); head->data = "2nd"; head->next = NULL; //두 번째 노드로 삽입 Node *q = (Node *)malloc(sizeof(Node)); q->data = "3rd"; q->next = NULL; head->next = q; //첫 번째 노드로 삽입 q = (Node *)malloc(sizeof(Node)); q->data = "1st"; q->next = head; head = q; //첫 번째 노드의 주소를 보관 //출력과 순회(traverse) Node *p = head; whlie(p!=NULL){ printf("%s\\n", p->data); p=p->next; }
- 함수에서 head가 전역 변수가 아니면 → 호출된 함수가 호출한 곳의 head 값에 영향을 끼쳐야 한다.
- 변수의 값 대신 변수의 주소를 매개변수로 넘겨줄 것
- = head 노드의 주소를 값으로 넘겨주는 것이 아니라,
head 노드의 주소가 저장된 변수의 주소를 매개변수로 → 호출한 함수에서 head의 값을 변경 O
void add_first1(Node **ptr_head, char *item){ Node *temp = (Node *)malloc(sizeof(Node)); temp->data = item; temp->next = *ptr_head; *ptr_head = temp; } add_first1(&head, item_to_store); //or 새로운 head 노드의 주소를 return Node *add_first2(Node *head, char *item){ Node *temp = (Node *)malloc(sizeof(Node)); temp->data = item; temp->next = head; return temp; } head = add_first2(head, item_to_store);
- 삽입과 삭제
- 삽입과 삭제 모두 삽입/삭제할 위치의 바로 앞 노드의 주소가 필요하다.
- 그렇기 때문에 주로 어떤 노드의 뒤에 삽입한다.
- 삽입
void add_after(Node *prev, char *item){ if(prev==NULL) return; Node *temp = (Node*)malloc(sizeof(Node)); temp->data = item; temp->next = prev->next; prev->next = temp; }
- 삭제
//첫 번째 노드의 삭제 Node *remove_first(){ if(head==NULL) return NULL; Node *temp = head; head = head->next; return temp; } //어떤 노드의 다음 노드 삭제 Node *remove_after(Node *prev){ Node *temp = prev->next; if(temp==NULL) return NULL: else{ prev->next=temp->next; return temp; } }
- 삽입과 삭제 모두 삽입/삭제할 위치의 바로 앞 노드의 주소가 필요하다.
- 순회(traverse): 연결 리스트의 노드들을 순차적으로 방문하는 것
else{ q->next = p->next; free(p); }
- 투 포인터를 사용하기
- 삽입/삭제하려는 위치의 앞(이전) 노드의 주소를 알아야 뒤에 삽입/삭제할 수 있다.
Node *p = head; Node *q = NULL: while(p!=NULL && 조건){ q = p; //q는 p를 한 칸 뒤에서 따라가는 역할 p = p->next; //p는 한 칸 전진 }
자료구조 12강
- 객체를 생성하고 기본값으로 초기화해주는 함수를 따로 만들어 사용하면 초기화 오류를 예방할 수 있다.
- 단방향 연결 리스트에서 삽입 연산
- 맨 앞에 삽입하는 경우(empty list 포함)
//p노드 이후에 삽입 //q노드는 p노드의 한 칸 뒤에 위치 if(q==NULL){ new_node->next = head->next; head = new_node; }
- 중간에 삽입하는 경우
else{ new_node->next = p->next; p->next = new_node; }
- 맨 앞에 삽입하는 경우(empty list 포함)
- 단방향 연결 리스트에서 삭제 연산(empty list가 아닐 때)
- 첫 번째 노드를 삭제
//삭제하고자 하는 노드 p //삭제하고자 하는 노드의 이전 노드 q if(q==NULL){ head = p->next; free(p); }
- 이외의 경우
- p 노드가 맨 마지막 노드이더라도 p→next는 NULL 이기 때문에 q→next = NULL;
else{ q->next = p->next; free(p); }
- 첫 번째 노드를 삭제
자료구조 13강
- 양방향 연결 리스트의 Node
typedef struct node{
char *data;
struct node *next;
struct node *prev;
}Node;
Node *head; //연결 리스트의 첫 번쨰 노드 주소 저장
Node *tail; //연결 리스트의 마지막 노드 주소 저장
- 양방향 연결 리스트에서의 삽입
- 앞 노드의 주소가 있어야 그 뒤에 삽입이 가능한 단방향 리스트와 다르게
- 양방향 연결 리스트에서는 prev와 next를 통해 어떤 노드의 앞에 노드를 삽입할 수 있다.
[어떤 노드 앞에 새로운 노드 삽입하기] ‼️새로운 노드 → 앞 연결 → 뒤 연결‼️ (순서 유의)
(0) 새로운 노드를 만들고 추가할 데이터를 저장한다.
(1) 새로운 노드의 링크를 먼저 연결한다.
(2) 새로운 노드의 앞 노드가 새로운 노드를 가리키도록 한다.
(3) 새로운 노드의 뒷 노드가 새로운 노드를 가르키도록 한다.//(0) 새로운 노드를 만들고 추가할 데이터 저장하기 Node *new_node = (Node *)malloc(sizeof(Node)); new_node->data = "by"; //(1) 새로운 노드의 링크를 먼저 연결 new_node->next = p; new_node->prev = p->prev; //(2) 새로운 노드의 앞 노드가 새로운 노드를 가리키도록 p->prev->next = new_node; //(3) 새로운 노드의 뒷 노드가 새로운 노드를 가리키도록 p->prev = new_node;
- [case 별로 어떤 노드 뒤에 새로운 노드 삽입하기] ‼️새로운 노드 → 뒤 연결 → 앞 연결‼️ (순서 유의)
Node head = (Node *)malloc(sizeof(Node)); Node tail = (Node *)malloc(sizeof(Node)); Node *p = head; void add_after(Node *pre, char *item);
- 연결 리스트에 노드가 하나도 없는 empty list
//head가 NULL이면 empty list, empty list이기 때문에 pre도 NULL if(pre==NULL && head==NULL){ head = new_node; tail = new_node }
- 맨 앞에 삽입하는 경우
//head != NULL일 떄 pre==NULL이면 제일 앞에 삽입해야 하는 경우 else if(pre==NULL){ new_node->next = head; head->prev = new_node; head = new_node; //첫 노드의 주소를 가지고 있는 head노드를 가장 마지막에 }
- 맨 마지막에 삽입하는 경우
//pre 뒤에 삽입해야하는데, pre가 마지막이면 마지막에 삽입해야 하는 경우 else if(pre==tail){ new_node->prev = tail; tail->next = new_node; tail = new_node; //마지막 노드의 주소를 가지고 있는 head노드를 가장 마지막에 }
- 중간에 삽입하는 경우
else{ new_node->prev = pre; new_node->next = pre->next; pre->next->prev = new_node; pre->next = new_node; }
- 연결 리스트에 노드가 하나도 없는 empty list
- 양방향 연결 리스트에서의 삭제
- 앞 노드의 주소가 있어야 그 뒷 노드를 삭제할 수 있는 단방향 리스트와 다르게
- 양방향 연결 리스트에서는 삭제하고자 하는 노드만 있다면 그 노드를 삭제할 수 있다.[노드 삭제하기] ‼️앞 → 뒤‼️ (순서 유의)
(1) 삭제할 노드의 앞 노드가 삭제할 노드의 뒷 노드를 가리키도록 한다.
(2) 삭제할 노드의 뒷 노드가 삭제할 노드의 앞 노드를 가리키도록 한다.p->prev->next = p->next; p->next->prev = p->prev;
- [case 별로 노드 삭제하기]
- 삭제할 노드 p가 유일한 노드
if(head==p && tail==p){ head = NULL; tail = NULL; free(p); }
- 제일 앞 노드인 경우 = p가 head인 경우
//p가 tail이 아닐 때 p가 head 라면 ~ 제일 앞 노드를 삭제 else if(p==head){ p->next->prev = NULL; head = p->next; free(p); }
- 제일 뒷 노드인 경우 = p가 tail인 경우
//p가 head가 아닐 때 p가 tail 이라면 ~ 제일 마지막 노드를 삭제 else if(p==tail){ p->prev->next = NULL; tail = p->prev; free(p); }
- 중간 삭제
else{ p->prev->next = p->next; p->next->prev = p->prev; free(p); }
- 삭제할 노드 p가 유일한 노드
- strcmp를 활용해서 정렬된 위치에 노드를 삽입할 수 있다.
- 원형 연결 리스트: 마지막 노드 ➡️ 이전 노드
- 원형 이중 연결 리스트: 마지막 노드 ↔ 이전 노드
자료구조 14강
- 프로그램을 여러 개의 소스파일로 분리할 경우
- 서로 연관된 함수들과 변수들이 하나의 파일에 있어(모듈화) → 구조가 좀 더 알기 쉽고 명료
- 수정된 파일만 개별적으로 컴파일 → 컴파일 시간 절약
- 소프트웨어 재사용 용이
- 여러 개의 소스 파일로 분할할 경우 해결해야 할 문제점
- 어떻게 다른 파일에 정의되어 있는 함수를 호출? && 어떻게 다른 파일들이 메크로나 타입 정의를 공유?
- header 파일과 source 파일을 분리한 후 다른 파일에서 header 파일을 include
- header 파일에는 프로토타입, source 파일에는 실제 구현
- header 파일에 다른 소스파일과 공유할 매크로, 타입 정의를 넣기
- 어떻게 다른 파일에 정의되어 있는 변수를 사용?
- header 파일에 공유 변수의 선언 → 공유 변수를 사용할 모든 source 파일은 header 파일을 include
- 오직 한 source 파일에서 공유 변수를 정의
- 변수의 선언(declaration): 컴파일러에게 변수의 존재를 알려줌
//정의하지 않고 선언만 하기 extern int i; extern int a[];
- 변수의 정의(definition): 실제로 메모리를 할당
- 변수의 선언(declaration): 컴파일러에게 변수의 존재를 알려줌
- 서로 다른 파일 간의 변수는 최대한 공유하지 않는 것이 좋다.
- 중첩된 include 문제
- 매크로 정의, 함수 프로토타입, 외부 변수의 선언은 여러 번 중복되어도 상관없다.
- 하지만 타입 정의가 중복되는 것은 컴파일러의 오류를 야기
- #indef - #endif
#indef (header파일이름) #define (header파일이름으로 매크로 정의) ... #endif
- 어떻게 다른 파일에 정의되어 있는 함수를 호출? && 어떻게 다른 파일들이 메크로나 타입 정의를 공유?
부경대학교 권오흠 교수님의 [c로 배우는 자료구조 및 여러 가지 예제 실습] 강의 정리입니다. 감사합니다.
728x90
'CS > 자료구조' 카테고리의 다른 글
[자료구조 - C언어] 자료구조 제15강: 스택(Stack) 개념과 구현(2) (0) | 2022.11.10 |
---|---|
[자료구조 - C언어] 자료구조 제15강: 스택(Stack) 개념과 구현(1) (0) | 2022.11.10 |
[자료구조 - C언어] 자료구조 제14강: Music Library Program(10) (0) | 2022.11.08 |
[자료구조 - C언어] 자료구조 제14강: Music Library Program(9) (0) | 2022.11.07 |
[자료구조 - C언어] 자료구조 제14강: Music Library Program(8) (0) | 2022.11.04 |