블로그에 저장된 글이 방대해짐과 여러 분야의 프로그래밍 언어를 다루게 되므로 카테고리의 소분류를 줄이고, 포스팅의 제목으로 각 챕터를 나누도록 하겠다.
또한 방학 동안 C언어 대신 파이썬을 했더니 C언어가 하나도 기억이 안나는 관계로, 알고리즘 및 실습에 앞서 기존의 연결리스트의 내용을 다시 짚고 넘어가는 과정을 거치도록 하겠다.
[1] 이중 연결리스트
Ⅰ. 구조체 선언
아래 구조체 선언은 연결리스트 노드의 구조체 선언이다.
이때 typedef struct를 사용하는 이유는 코드를 더 간결하고 사용하기 쉽게 만들기 위해서이다.
typedef struct을 사용하지 않는 경우 | typedef struct을 사용하는 경우 |
struct ListNode { element data; struct ListNode* prev; struct ListNode* next; }; // 변수 선언 struct ListNode node; |
typedef struct ListNode { element data; struct ListNode* prev; struct ListNode* next; } ListNode; // 변수 선언 ListNode node; |
위에서 볼 수 있듯, 구조체를 정의할 때 typedef struct를 사용하면 구조체를 사용할 때마다 struct 키워드를 반복해서 쓰지 않아도 된다.
또한 typedef를 사용하면 구조체 이름을 더 쉽게 변경할 수 있다. 예를 들어, ListNode라는 이름을 나중에 Node로 변경하고 싶다면, 구조체 정의 부분에서만 typedef 된 이름을 바꾸면 되므로 유지보수가 더 쉽다.
typedef struct ListNode {
element data;
struct ListNode* prev;
struct ListNode* next;
} ListNode;
ListNode 구조체는 실제로 연결리스트에서 사용되는 노드의 데이터 값과, 해당 노드의 연결된 앞 뒤 노드의 위치를 저장하는 중요한 구조체이다. 하지만 ListNode 구조체는 해당 노드 시점에서 리스트에 저장(연결)된 데이터(노드)의 개수를 알 수 없다.
리스트에 저장된 노드의 개수를 확인하기 위해서는 Head에서 Tail까지 순회하며 판단해야 한다.
따라서 이러한 문제를 해결하기 위해 노드의 시점에서 벗어나 노드 전체를 관리하는 구조체를 만드는 것이 효율적이다. 그렇게 탄생하는 구조체가 ListType이다.
ListType 구조체는 아래 코드와 같다.
기본적으로 리스트의 Head와 Tail에 바로 접근할 수 있도록 Head와 Tail 노드의 위치를 구조체 변수로 가진다. 바로 접근할 수 있는 대신, 프로그램 시작 전에 꼭 초기화 과정을 거쳐야 한다.
typedef struct ListType {
struct ListNode* Head;
struct ListNode* Tail;
int size;
} ListType;
Ⅱ. 구조체 초기화
앞서 이야기했듯, 우리는 연결리스트를 다룰 때, 노드를 관리하는 구조체 ListNode와 리스트의 전반적인 관리를 돕는 ListType를 나누어 관리한다. ListType에서 우리는 연결리스트의 앞과 뒤의 위치를 가지는 Head와 Tail을 확인할 수 있다.
함수 실행 전, 먼저 main 함수에서 ListType을 선언하는 것을 잊지 않도록 한다.
ListType list; |
Head와 Tail은 프로그램 시작 전에는 아무런 값이 존재하지 않는다.
따라서 오류를 방지하기 위해 해당 노드의 공간에 NULL을 할당한다. 또한 리스트의 노드 개수(size) 또한 0개 이므로, 0개로 초기화한다.
이때 유의할 점은 이중연결리스트에서 Head와 Tail은 실제로 데이터를 저장하는 노드가 아니라는 점이다. 이 노드는 리스트의 시작과 끝을 가리키는 포인터이며, 연결리스트의 접근을 Head와 Tail을 통해 진행한다. 따라서 Head와 Tail 노드에 데이터를 저장하지 않도록 한다.
list->Head = (ListNode*)malloc(sizeof(ListNode));
list->Tail = (ListNode*)malloc(sizeof(ListNode));
✅ list의 Head와 Tail은 동적할당이 꼭 필요하다! ✅
✔ 이중 연결리스트에서 Head와 Tail은 실제로 값을 저장하는 유효한 노드가 아니다.
✔ Head와 Tail 노드를 이용해 다른 노드에 접근한다.
✔ 실제로 사용하는 노드는 Head와 Tail 사이의 노드이다. (동적할당 필요)
// 리스트 초기화
void init(ListType* list) {
list->Head = (ListNode*)malloc(sizeof(ListNode));
list->Tail = (ListNode*)malloc(sizeof(ListNode));
// 더미 노드 초기화
list->Head->next = list->Tail;
list->Head->prev = NULL;
list->Tail->next = NULL;
list->Tail->prev = list->Head;
list->size = 0;
}
위 코드를 확인하면 더미 노드를 초기화하는 것을 확인할 수 있다.
초기화 함수에서 Head와 Tail을 상호 연결한다. 이때 아래 순서를 따른다.
ⅰ. Head의 다음 노드를 Tail로 지정한다.
ⅱ. Head의 이전 노드를 NULL로 지정한다.
이는 사용되지 않는다는 것을 의마하며, 실제로 Head 이전의 노드는 존재하지 않는다 가정하고, 사용하지 않는다.
ⅲ. Tail의 다음 노드를 NULL로 지정한다.
ⅳ. Tail의 이전 노드를 Head로 설정한다.
Head와 Tail을 연결한다!
이때 코드의 입력값을 보면 리스트의 포인터를 받는다.
이 말은 즉슨, main 함수에서 노드를 ListType으로 선언한 리스트는 실제 리스트이므로, 초기화 함수에 전달하기 위해서는 리스트(구조채)의 위치를 입력값으로 줘야 한다. 이 부분은 리스트를 포인터로 선언하면 & 주소 연산자를 쓸 필요가 없으나, 코드의 간결성을 위해 리스트 함수는 & 연산자를 이용해 주소를 전달하여 리스트에 접근하도록 한다.
아래 코드는 main 함수에서 리스트의 초기화를 담당하는 코드이다.
int main(){ ListType list; init(&list); } |
다시 정리하면 다음과 같다.
✔ 리스트의 관리는 리스트 함수에서 실행한다.
✔ 리스트의 접근을 위해 입력값은 리스트(구조체)의 주소(포인터)로 전달한다.
✔ 리스트 관리 함수는 입력값을 리스트의 주소 받으며, 주소를 통해 값을 추가/삭제한다.
Ⅲ. 노드 추가
새로운 노드를 추가할 때 리스트의 맨 앞, 리스트의 중간, 리스트의 맨 뒤로 추가하는 경우를 나누어 생각해 보자.
또한 3가지로 분리한 노드 추가 함수들은 add 함수에서 호출로 다루도록 한다.
① add_front
add_front 함수는 리스트의 맨 앞에 노드를 추가하는 함수이다.
먼저 새로운 노드를 저장할 노드 newNode 변수를 동적할당한다. 이후 헷갈리지 않도록 새롭게 할당한 newNode에 data값을 저장한다.
이후에는 newNode를 기존의 노드에 연결하는 과정을 거친다.
void add_front(ListType* list, element data){
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
newNode->data = data;
newNode->next = list->Head->next;
newNode->prev = list->Head->next->prev;
list->Head->next = newNode;
list->Head->next->prev = newNode;
list->size ++;
}
ⅰ. newNode의 이전 노드를 Head로 설정한다.
ⅱ. newNode의 다음 노드를 Tail로 설정한다.
ⅲ. list->Head->next->prev를 newNode로 지정한다.
이때 유의할 점은 Tail->prev로 접근하지 않는 것이다.
ⅳ. list->Head->next를 newNode로 지정한다.
❌ front에서 new는 Tail로 접근하지 않는다!!! ❌
newNode->prev = list->Head;
newNode->next = list->Head->next;
list->Head->next->prev = newNode;
list->Head->next = newNode;
✅ Tail->prev이 아닌, list->Head->next->prev = newNode이다 : 플로우를 따른다.
✅ list->Head->next->prev에 접근 후에 list->Head->next를 변경한다.
✅4개의 줄(코드)로 위치를 변경한다!
[1] newNode의 앞 뒤 지정
[2] list와 newNode의 마무리 연결(Tail 접근 ❌)
void add_front(ListType* list, element data){
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
newNode->data = data;
newNode->next = list->Head->next;
newNode->prev = list->Head;
list->Head->next->prev = newNode;
list->Head->next = newNode;
//list->Head->next->prev = newNode; (X)
list->size++;
}
② add_middle
add_middle 함수는 리스트의 중간에 노드를 추가하는 함수이다.
void add_middle(ListType* list,int rank, element data){
if(rank >= (list->size+1) || rank < 1){
printf("Invaild Position."); return ;
}
ListNode *tmp = list->Head;
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
// ListNode* pre = (ListNode*)malloc(sizeof(ListNode));
newNode->data = data;
for(int i=0;i<rank-1;i++){tmp = tmp->next;}
newNode->next = tmp->next;
newNode->prev = tmp;
tmp->next->prev = newNode;
tmp->next = newNode;
list->size ++;
}
ⅰ. tmp라는 변수를 사용하여 Head에서 시작하여 삽입할 순위 rank 직전까지 이동한다.
ⅱ. newNode의 이전 노드를 tmp로 설정하고, newNode의 다음 노드를 tmp->next로 설정한다.
ⅲ. 기존 노드 간의 연결을 갱신한다.
즉, tmp->next->prev를 newNode로 지정하고, tmp->next를 newNode로 지정한다.
위 과정에서 유의할 점은 리스트의 끝부분에 접근하지 않고, 정확한 순위로 이동하여 중간에 삽입을 처리하는 것이다.
newNode->next = tmp->next;
newNode->prev = tmp;
tmp->next->prev = newNode;
tmp->next = newNode;
☑ add_front와 마찬가지로, newNode의 앞과 뒤를 먼저 연결한다.
☑ tmp로 접근한 노드의 앞과 뒤를 연결한다.
☑ tmp는 rank 번째 노드의 뒷 노드임을 주의한다!
③ add_rear
add_rear 함수는 리스트의 맨 끝에 노드를 추가하는 함수이다.
리스트의 맨 끝에 접근하는 방법은 list의 Head를 list의 size 만큼 순회하는 경우도 있지만, Tail 노드를 이용하는 경우도 있다.
void add_rear(ListType* list, element data){
ListNode* new = (ListNode*)malloc(sizeof(ListNode));
new->data = data;
new->next = list->Tail;
new->prev = list->Tail->prev;
list->Tail->prev->next = new;
list->Tail->prev = new;
list->size++;
}
list의 size 만큼 순회하는 경우와 Tail 노드를 이용하는 경우의 비교는 아래와 같다.
코드의 가독성과 편의성을 위해 Tail 노드를 이용하는 방법을 사용하도록 하자.
list의 size 이용 | Tail 노드 이용 |
ListNode *tmp = list->Head; while(tmp->next->next!=NULL) tmp = tmp->next; newNode->next = list->Tail; newNode->prev = tmp; tmp->next = newNode; |
new->next = list->Tail; new->prev = list->Tail->prev; list->Tail->prev->next = new; list->Tail->prev = new; |
ⅰ. newNode의 이전 노드를 Tail->prev로 설정한다.
ⅱ. newNode의 다음 노드를 Tail로 설정한다.
ⅲ. list->Tail->prev->next를 newNode로 지정한다.
ⅳ. list->Tail->prev를 newNode로 지정한다.
이 과정에서 주의할 점은, Tail 노드는 실제 데이터가 아닌 더미 노드이므로, Tail->prev를 이용하여 리스트 끝에 바로 접근하는 것이다.
new->next = list->Tail;
new->prev = list->Tail->prev;
list->Tail->prev->next = new;
list->Tail->prev = new;
✅ add_rear에서는 newNode의 next와 prev는 Tail을 이용한다!
✅ add_front와 마찬가지로, newNode의 앞과 뒤를 먼저 연결한다.
✅ Tail의 이전 노드와 Tail 이전 노드의 다음 노드를 초기화한다.
❗️ newNode의 rear는 Tail을 이용한다! ❗️
앞에서 다룬 add 관련함수는 add 함수에서 조건문을 분기로 실행된다.
void add(ListType* list,int rank, element data){
if(rank == 1 || list->size == 0) add_front(list,data);
else if(1 < rank && rank <= list->size) add_middle(list,rank,data);
else add_rear(list,data);
}
Ⅳ. 노드 제거
① delete_front
delete_front는 리스트의 맨 앞 노드를 삭제하는 함수이다. 인자는 list 하나만 받는다.
tmp는 리스트의 맨 앞 노드(삭제할 노드)를 임시로 저장할 노드 (ListNode) 구조체 변수이다. 나중에 노드를 삭제한 후에도 삭제한 노드에 접근하기 위해서 필요하다.
element delete_front(ListType* list){
ListNode *tmp = list->Head->next;
element value = tmp->data;
list->Head->next->prev = list->Head;
list->Head->next = list->Head->next->next;
list->size--;
return value;
}
이 함수는 먼저 Head의 바로 다음 노드인 tmp를 임시 변수로 저장하고, 이 노드의 data 값을 반환할 값으로 저장한다.
이후에는 tmp가 가리키는 노드를 리스트에서 제거하는 과정을 진행한다.
ⅰ. tmp에 노드를 할당한다. 이때 노드는 삭제할 (리스트의 맨 처음) 노드이다.
ⅱ. Head->next->prev를 Head로 설정하여 삭제할 노드의 다음 노드를 Head와 연결한다.
ⅲ. Head->next를 tmp->next로 설정하여 리스트의 첫 번째 노드를 다음 노드로 교체한다.
ⅳ. 리스트의 크기인 size를 1 줄이고, 삭제한 노드의 데이터를 반환한다.
여기서 유의할 점은, Head가 더미 노드로 실제 데이터를 갖지 않기 때문에, 리스트의 첫 번째 유효한 노드만 삭제하는 것이다.
❌ front에서 new는 Tail로 접근하지 않는다!!! ❌
list->Head->next->prev = list->Head; l
ist->Head->next = list->Head->next->next;
list->size--;
✅ delete_front는 삭제할 노드를 빼준다고 생각하면 된다.
✅ 앞 뒤 연결은 두 줄만 작성하면 되다.
② delete_middle
delete_middle 함수는 리스트의 중간에 위치한 노드를 삭제하는 역할을 한다.
주어진 rank 값에 따라 해당 위치의 노드를 찾아 삭제한 뒤, 이전과 이후 노드를 다시 연결해 준다.
element delete_middle(ListType *list, int rank){
if(rank < 1 || rank > list->size){printf("Invaild Connection"); return -1;}
ListNode *tmp = list->Head;
for(int i=0;i<rank;i++){tmp = tmp->next;}
element value = tmp->data;
//삭제될 노드까지 접근
tmp->prev->next = tmp->next;
tmp->next->prev = tmp->prev;
return value;
}
tmp 변수는 삭제할 (rank 위치) 노드를 임시로 저장하기 위한 임의의 노드 (ListNode) 변수이다.
tmp는 list->Head를 저장하여 list에 접근할 수 있도록 한다.
ⅰ. 삭제할 노드의 rank 조건을 확인한다. 맨 앞, 맨 뒤의 노드가 아닌 rank 순위의 노드를 제거한다.
ⅱ. 삭제할 노드에 접근한다. Head 노드에서 시작해, 삭제할 노드의 위치까지 for문을 통해 이동한다.
ⅲ. 삭제할 노드의 다음 노드가 삭제할 노드의 이전 노드를 가리키도록 한다.
ⅳ. 리스트에서 노드를 삭제한 후, 리스트 크기를 줄이고, 삭제된 노드의 데이터를 반환한다.
tmp->prev->next = tmp->next;
tmp->next->prev = tmp->prev;
✅ delete_middle는 for 반복문으로 rank 위치에 접근한다.
✅ 앞 뒤 연결은 두 줄만 작성하면 된다. 32 32
③ delete_rear
delete_rear 함수는 리스트의 맨 마지막 노드를 삭제하는 함수이다.
이때 리스트의 맨 마지막 노드는 list의 Tail 노드를 이용해 접근한다. 논리적 관계에 유의하자.
element delete_rear(ListType *list) {
ListNode *tmp = list->Tail->prev; // 마지막 노드를 tmp로 참조
element value = tmp->data;
tmp->prev->next = list->Tail; // 마지막 노드의 이전 노드가 Tail을 가리키도록 설정
list->Tail->prev = tmp->prev; // Tail의 prev가 삭제할 노드의 이전 노드를 가리키도록 설정
free(tmp); // 삭제할 노드를 메모리에서 해제
list->size--;
return value;
}
ⅰ. tmp는 삭제할 노드이자, 리스트의 맨 뒤 노드이므로, list->Tail->prev로 접근한다.
ⅱ. ListNode *tmp = list->Tail->prev;
ⅲ. 마지막 노드의 이전 노드가 Tail을 가리키도록 설정한다.
ⅳ. Tail의 이전 노드가 삭제할 노드의 이전 노드를 가리키도록 설정한다.
tmp->prev->next = list->Tail;
list->Tail->prev = tmp->prev;
✅ 삭제할 노드 (tmp)는 Tail로 접근한다!
✅ 앞 뒤 연결은 두 줄만 작성하면 되다.
❗️ newNode의 rear는 Tail을 이용한다! ❗️
앞에서 다룬 delete 관련함수는 delete 함수에서 조건문을 분기로 실행된다.
void delete(ListType *list, int rank){
if(rank < 1 || rank > list->size){printf("Invaild Connection"); return -1;}
if(rank == 1) delete_front(list);
else if(1 < rank && rank < list->size) delete_middle(list,rank);
else delete_rear(list);
}
Ⅴ. 노드 반환
get 함수는 이중 연결 리스트에서 특정 위치에 있는 노드의 데이터를 가져오는 함수이다.
이 함수는 사용자가 입력한 순서(랭크)에 따라 해당 위치의 데이터를 반환한다.
element get(ListType *list, int rank){
if(rank > list->size || rank < 1){printf("Invaild Connection"); return -1;}
ListNode* tmp = list->Head;
for(int i=0;i<rank;i++) tmp = tmp->next;
return tmp->data;
}
ⅰ. 이 함수는 이중 연결 리스트에서 특정 순서에 해당하는 노드의 데이터를 가져오는 역할을 한다.
ⅱ. 먼저, rank가 리스트의 크기를 벗어나거나 1보다 작은 경우, 오류 메시지를 출력하고, -1을 반환한다.
ⅲ. 리스트의 헤드에서부터 시작해, 지정된 rank 위치까지 노드를 순차적으로 탐색한다.
ⅳ. 탐색이 완료되면 해당 노드의 데이터를 반환한다.
Ⅵ. 노드 출력
print 함수는 리스트 노드에 저장된 값을 모두 출력하는 함수이다. 출력의 형태는 사용자가 지정한다.
void print(ListType *list){
// printf("data : %c",list->Head->next->data);
ListNode *tmp = list->Head;
// printf("first data : %c",tmp->next->data);
while(tmp->next->next != NULL){
printf("[%c]",tmp->next->data);
tmp = tmp->next;
}printf("\n");
}
ⅰ. 이 함수는 이중 연결 리스트의 모든 노드를 순차적으로 출력하는 역할을 한다.
ⅱ. 리스트의 헤드에서 시작하여 마지막 노드 전까지 각 노드의 데이터를 출력한다.
이중연결리스트 ADT
- 다음 네 가지 연산을 지원해야 함 (순위는 1부터 시작한다고 가정) - delete(list, r) : list의 순위 r에 위치한 원소를 삭제한다. (주교재의 remove와 동일) - print(list) : list의 모든 원소를 저장 순위대로 공백없이 출력한다. 연산을 무시한다.
- ※ 순위 정보가 유효하지 않으면 화면에 에러 메시지 "invalid position"을 출력하고, 해당
- - get(list, r) : list의 순위 r에 위치한 원소를 반환한다.
- - add(list, r, e) : list의 순위 r에 원소 e를 추가한다.
- 입력에 대한 설명 (아래 입출력 예시 참조)
- 각 연산의 내용이 한 줄에 한 개씩 입력되고, 한 개의 줄에는 연산의 종류, 순위, 원소 - 순서로 입력된다.
- 연산의 종류: 연산 이름의 맨 앞 영문자가 대문자 A, D, G, P로 주어진다. - 순위: 양의 정수
- 원소: 영문자(대문자, 소문자 모두 가능)
2024.09.06 SUCCESS 100/100 확인
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef char element;
typedef struct ListNode{
element data;
struct ListNode* next;
struct ListNode* prev;
}ListNode;
typedef struct ListType{
int size;
struct ListNode* Head;
struct ListNode* Tail;
}ListType;
void init(ListType* list){
list->Head = (ListNode*)malloc(sizeof(ListNode));
list->Tail = (ListNode*)malloc(sizeof(ListNode));
list->Head->next = list->Tail;
list->Head->prev = NULL;
list->Tail->next = NULL;
list->Tail->prev = list->Head;
list->size = 0;
}
void add_front(ListType* list, element data){
ListNode *new = (ListNode*)malloc(sizeof(ListNode));
new->data = data;
new->next = list->Head->next;
new->prev = list->Head;
list->Head->next->prev = new;
list->Head->next = new;
list->size ++;
}
void add_middle(ListType *list, element data,int rank){
ListNode *tmp = list->Head;
for(int i = 0; i < rank - 1; i++) tmp = tmp->next; // 추가할 위치의 전까지 이동
// printf("position data [%c]",tmp->data);
ListNode * new = (ListNode*)malloc(sizeof(ListNode));
new ->data = data;
new->next = tmp->next;
new->prev = tmp;
tmp->next->prev = new;
tmp->next = new;
list->size++;
}
void add_rear(ListType* list, element data){
ListNode* new = (ListNode*)malloc(sizeof(ListNode));
new->data = data;
new->next = list->Tail;
new->prev = list->Tail->prev;
list->Tail->prev->next = new;
list->Tail->prev = new;
list->size++;
}
element delete_front(ListType* list){
ListNode* tmp = list->Head->next;
element value = tmp->data;
list->Head->next->prev = list->Head;
list->Head->next = list->Head->next->next;
list->size --;
return value;
}
element delete_middle(ListType *list, int rank){
ListNode *tmp = list->Head;
for(int i=0; i<rank; i++) tmp = tmp->next;
element value = tmp->data;
tmp->next->prev = tmp->prev;
tmp->prev->next = tmp->next;
list->size --;
return value;
}
element delete_rear(ListType* list){
ListNode* tmp = list->Tail->prev;
element value = tmp->data;
tmp->prev->next = list->Tail;
list->Tail->prev = tmp->prev;
list->size --;
return value;
}
void add(ListType* list, element data, int rank){
if(rank < 1 || rank > (list->size+1)){printf("invalid position");return;}
if(rank == 1) add_front(list,data);
else if(rank == list->size + 1) add_rear(list,data);
else add_middle(list,data,rank);
}
element delete(ListType* list, int rank){
if( list->size <= 0 || rank < 1 || rank > list->size ){printf("invalid position");return -1;}
if(rank == 1) return delete_front(list);
else if(rank == list->size) return delete_rear(list);
else return delete_middle(list,rank);
}
element get(ListType* list, int rank){
if( list->size <= 0 || rank < 1 || rank > list->size){printf("invalid position\n");return -1;}
ListNode *tmp = list->Head;
for(int i=0 ;i <rank ; i++ )tmp = tmp->next;
return tmp->data;
}
void print(ListType *list){
ListNode * tmp = list->Head->next;
for(int i=0; i< list->size ; i++){printf("%c",tmp->data);tmp = tmp->next;} printf("\n");
}
int main(){
ListType list;
init(&list);
int N, rank;
char data, fuc, tmp;
scanf("%d",&N); getchar();
for(int i=0;i<N;i++){
scanf("%c%c",&fuc,&tmp);
if(fuc == 'A'){
scanf("%d%c%c",&rank,&tmp,&data); getchar();
add(&list,data,rank);
}
else if(fuc == 'D'){
scanf("%d",&rank);getchar();
int value = delete(&list,rank);
}
else if(fuc == 'G') {
scanf("%d",&rank);getchar();
int value = get(&list,rank);
if(value != -1)printf("%c",value);
}
else if(fuc == 'P'){print(&list);}
}
// print(&list);
}
/*
9
A 1 D
A 2 a
A 3 y
D 1
P
G 3
A 1 S
P
↦ 연산의 개수: 9
↦ add(list, 1, 'D')
↦ add(list, 2, 'a')
↦ add(list, 3, 'y')
↦ delete(list, 1)
↦ print(list)
↦ get_entry(list, 3)
↦ add(list, 1, 'S')
↦ print(list)
↦ get_entry(list, 3)
5
A 1 S
A 2 t
A 3 r
A 3 a
P
↦ 연산의 개수: 5
↦ add(list, 1, 'S')
↦ add(list, 2, 't')
↦ add(list, 3, 'r')
↦ add(list, 3, 'a')
↦ print(list)
*/
'Algorithm' 카테고리의 다른 글
#1. 기본 추상 자료형 (CHAPTER 4) (3) | 2024.10.06 |
---|---|
알고리즘 실습 #2. 우선순위 큐(선택 & 삽입 정렬) (0) | 2024.09.13 |