일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 삽입식 힙
- 힙정렬
- 이중해싱
- 딥러닝
- vsCode
- 이중연결리스트
- 상향식 힙
- pytorch
- Loss함수
- bodyparser
- 알고리즘
- body-parser
- 경사하강법
- anaconda
- 분리연쇄법
- 선형회귀
- MSE
- 선형조사법
- nodejs
- urlencoded
- 연결리스트
- downheap
- 해시테이블
- 2차조사법
- upheap
- ML
- POST
- 개방주소법
- Today
- Total
LittleDeveloper
Week1_ Review 본문
1. 이중연결리스트를 이용한 영문자 리스트 ADT
<4가지 연산>
-add(L, r, e): list의 순위 r에 원소 e 추가
-delete(L, r): list의 순위 r에 위치한 원소 삭제
-get(L, r): list의 순위 r에 있는 원소 반환
-print(L): list의 모든 원소를 출력
*순위 정보가 유효하지 않으면 "invalid position" 출력, 해당 연산 무시
->연산 이름은 각각 A, D, G, P 로 주어짐.
STEP1 [자료구조 선언]
- 일단 "구조체"가 필요해요! 이 구조체를 왜 만드냐구요?
'노드 하나가 담을 원소(영문자)',
'이전 노드를 가리키는 링크',
'다음 노드를 가리키는 링크'
이 3가지 정보를 포함할 노드의 구조로 구조체가 가장 적절해보이네요~
혹시 typedef 가 뭐였는지 잊으셨나요? 구조체 선언 복습하고 오기~
https://dojang.io/mod/page/view.php?id=409
typedef struct node {
struct node* prev; //이전 노드를 가리키는 노드
char elem; //원소
struct node* next; //다음 노드를 가리키는 노드
}node;
=> 이제 이 노드들이 포함된 하나의 '리스트'를 만들어보아요~ 어떻게? 또 구조체로!
*우리가 만들 연결리스트는 헤더 및 트레일러 노드가 있어요!! 이 노드들은 데이터를 가지지 않는 특별한 노드들입니다!
typedef strcuct list{
node *head; //헤더 노드
int position; //총 노드 개수
node *tail; //트레일러 노드
}list;
STEP2 [연산 함수 만들기]
**본격적으로 리스트를 만들기 전에 꼭 해야 할 것이 있어요! 그건 바로 리스트 초기화!!!!
거의 모든 자료구조(연결리스트, 트리 등등)는 삽입이나 삭제 같은 연산을 하기 전에 초기화하는 작업이 필요해요~
1) 리스트 초기화하기
1. 헤더 노드, 트레일러 노드 각각 선언해주고 동적할당~
2. 1에서 만들어준 헤더를 리스트의 헤더 위치에 연결! 헤더 노드도 이전 노드 링크와 다음 노드 링크가 있겠죠?
헤더 노드는 리스트의 가장 맨 앞 노드니까(이 노드의 이전 노드는 존재하지 않으므로) header->prev = NULL; 이 됩니다.
다음 노드 링크는 어떻게 될까요?
우리가 만든 리스트는 아직까지 "헤더랑 트레일러 노드"밖에 없으니까, 헤더 다음 노드는 트레일러 노드네요!
그러니까 header->next = header;
3. 1에서 만들어준 트레일러도 2처럼 리스트의 트레일러 위치에 연결해주고, 이전 노드 링크와 다음 노드 링크를 처리해주세요!
4. 마지막으로 잊지 말기!! 헤더, 트레일러 노드 이렇게 노드 2개가 리스트에 있으니까 L->position = 2; 가 되겠네요!
void init(list *L){
node *header, *tailer;
header = (node*)malloc(sizeof(node));
tailer = (node*)malloc(sizeof(node)); ///1
L->head = header;
header->prev = NULL;
header->next = tailer; ///2
L->tail = tailer;
tailer->prev = header;
tailer->next = NULL; ///3
L->position = 2; ///4
}
2) add함수 만들기
1. 필요한 변수들 선언
2. 순위와 문자 입력받기 -> 입력받은 순위가 유효하지 않은 경우
3. 임시 노드 생성 + 리스트의 헤드에 연결, 이 임시 노드를 입력받은 순위(자리)로 이동이동~~
4. 새 노드 생성 + 동적할당 후 요소에 입력받은 문자 삽입
5. 노드들 앞뒤를 서로 연결
6. 노드 add했으므로 잊지 말고 노드 개수++
**헷갈리는 포인트 정리!!!
Q1. 2에서 (p->position)-1 < r 이 무슨 뜻인가요??
A1. 예를 들어 지금 총 노드 개수 5개라고 해봅시다. (헤더 노드, S, t, r, 트레일러 노드 이렇게 5개!)
만약에 r = 3을 입력받으면, 우리는 5-1=4 > 3 이니까 순위 정보는 유효하죠! (순위가 유효하네! = 그 순위에 노드 있네!)
But.... r = 5 를 입력받으면, 5-1=4 < 5 이므로 "invalid position"을 출력하게 되네요.
또다른 예를 들어볼까요? 현재 총 노드 개수가 2개, 헤더 노드와 트레일러 노드밖에 없다고 해봅시다.
만약 r = 1을 입력받으면, 2-1=1 = 1 이므로 순위가 유효하네요.
아 그니까 (p->position)-1 의 의미가 뭐냐고요 (p->position)-1 은 노드 '사이'를 의미합니다.
노드가 5개면(헤더, 트레일러 포함) 노드 '사이'는 4개가 있네요. 아래 표에서 초록색 체크 표시!! 새로운 노드를 이미 있던 노드들 사이에 집어넣을 건데, 존재하지도 않는 곳에 집어넣을 순 없겠죠? 예를 들어 트레일러 노드 다음 같은..
Q2. 5번 과정(노드 서로 연결)이 헷갈려요..
A2. 자, 차근차근 하나씩 살펴봅시다.
아래처럼 리스트에 S, t, r이 이미 삽입된 리스트에서, 'r' 자리에 'a'를 삽입하는 상황이라고 해봐요.
r=1 | 2 | 3 | ||
[ 헤더 ] | S | t | r | [트레일러] |
새로 생성한 노드(newnode)(ex)요소가 'a'인 노드)도 당연히 이전 링크랑 다음 링크가 있을거예요!
이전 링크 | a | 다음 링크 |
새 노드의 이전 링크(prev)는 어디에다 연결하죠? 맞아요!
1) '입력받은 순위에 원래 있던' 노드(tmp) 친구('r')의 '이전 노드'('t')와 연결해주는 작업이 필요해요. ex) t-a
2) 새 노드의 다음 링크(next)는요? '입력받은 순위에 원래 있던' 노드('r')와 연결해주세요! ex) a-r
이제 끝인가요? 아니죠!!
3) '입력받은 순위의 노드'의 이전 노드(t)의 다음 링크(next),
4) '입력받은 순위의 노드'(r)의 이전 링크(prev)가 모두 newnode를 향하도록 해주면 진짜 끝!!!
void add(list *L){
int i, r;
char ch; ///1
scanf("%d %d",&r,&ch);
getchar();
if((L->position)-1 < r){
printf("invalid position\n");
return;
} ///2
node *tmp;
tmp = L->head;
for(i=0; i<r; i++)
tmp = tmp->next; ///3
node *newnode = (node*)malloc(sizeof(node));
newnode->elem = ch; ///4
newnode->next = tmp;
newnode->prev = tmp->prev;
tmp->prev->next = newnode;
tmp->prev = newnode; ///5
(L->position)++; ///6
}
3) del 함수 만들기
삭제 연산은 삽입 연산보다 좀더 간단해요!
1. 삭제할 위치 정보 입력받기
2. 헤더, 트레일러 제외 노드들 개수( =(L->position)-2 )가 1의 위치값보다 작은 경우 "invalid position" 출력
3. 임시 노드 선언 후 리스트의 헤더에 연결 + 삭제할 노드까지 tmp 이동시키기
4. 삭제할 노드의 '이전 노드'와 '다음 노드' 연결시키는 작업!! + 메모리 해제까지
5. 노드 개수 -1
void del(list *L){
int i, order;
scanf("%d", &order);
getchar(); ///1
if((L->position)-2< order){
printf("invalid position\n");
return;
} ///2
node *tmp;
tmp = L->head;
for(i=0; i<order; i++) tmp = tmp->next; ///3
tmp->prev->next = tmp->next;
tmp->next->prev = tmp->prev;
free(tmp); ///4
(L->position)--; ///5
4) get_entry 함수 만들기
1. 탐색할 위치 정보 입력받기
2. 헤더, 트레일러 제외 노드들 개수( =(L->position)-2 )가 1의 위치값보다 작은 경우 "invalid position" 출력
3. 임시 노드 선언 후 리스트의 헤더에 연결 + 탐색할 노드까지 tmp 이동시키기
4. 탐색한 노드 출력
void get_entry(list *L){
int i, num;
scanf("%d", &num);
getchar(); ///1
if((L->position)-2 <num){
printf("invalid position\n");
return;
} ///2
node *tmp;
tmp = L->head;
for(i=0;i<num;i++) tmp=tmp->next; ///3
printf("%c\n", tmp->elem); ///4
}
4) print함수 만들기
1. 임시 노드 tmp 선언하여 리스트의 헤더와 연결
2. 헤더, 트레일러 제외하고 노드의 elem 출력
**이때 헤더 다음 노드부터 출력하기 위해 처음 반복문 시작할 때(i=0일 때) tmp = tmp->next 로 시작.
void print(list *L){
int i;
node*tmp=L->head; //1
for(int i; i<(L->position)-2); i++){
tmp = tmp->next; //head 다음부터 시작
printf("%c",tmp->elem);
}
printf("\n"); //2
}
STEP3 [메인함수 구성]
1. 리스트 선언
2. 리스트 초기화
3. 연산 횟수 n 입력받기
4. n번 동안 연산
int main() {
list* L = (list*)malloc(sizeof(list));
init(L);
int i,r,n;
char ch;
scanf("%d", &n);
getchar();
for (i = 0; i < n; i++) {
scanf("%c", &ch);
getchar();
if (ch == 'A') {
add(L);
continue;
}
else if (ch == 'D') {
del(L);
continue;
}
else if (ch == 'G') {
get_entry(L);
continue;
}
else {
print(L);
continue;
}
}
return 0;
}
후~~ 쉽지 않았다. 연결리스트는 역시 백번 말로 코드로 공부하는 것보다 혼자 손으로 그림 그려보면서 알고리즘 확인하는게 최선의.. 확실한 방법인 거 같네요! 코드가 길어 보이지만 함수끼리 비슷한 코드가 많아서 금방 외울 수 있을 거예요! 화이팅~~
'알고리즘(C)' 카테고리의 다른 글
Week9_해시테이블_실습(2) (0) | 2021.11.29 |
---|---|
Week9_해시테이블_실습(1) (0) | 2021.11.29 |
Week10_ 그래프 (0) | 2021.11.05 |
Week7_해시테이블(1) (0) | 2021.10.27 |
Week2_우선순위 큐_개념 (0) | 2021.10.13 |