덱을 구현해보자..
우선 헤더파일이다.
#ifndef __DEQUE_H__
#define __DEQUE_H__
#define TRUE 1
#define FALSE 0
typedef int Data;
typedef struct _node
{
Data data;
struct _node * next;
struct _node * prev;
} Node;
typedef struct _dlDeque
{
Node * head;
Node * tail;
} DLDeque;
typedef DLDeque Deque;
void DequeInit(Deque * pdeq);
int DQIsEmpty(Deque * pdeq);
void DQAddFirst(Deque * pdeq, Data data);
void DQAddLast(Deque * pdeq, Data data);
Data DQRemoveFirst(Deque * pdeq);
Data DQRemoveLast(Deque * pdeq);
Data DQGetFirst(Deque * pdeq);
Data DQGetLast(Deque * pdeq);
#endif
요구사항은 양뱡향 연결리스트를 잘 바꾸면 된다. 이때 더미가 있는 양뱡향 연결을 사용하는게 좋을까?
양뱡향 연결리스트 만들때 LInsert에서 썼던 트릭을 생각해보자.
void LInsert(List* plist, Data data)
{
Node* temp = (Node*)malloc(sizeof(Node));
temp->data = data;
temp->next = plist->head; //첫 노드에는 NULL 할당
**if (plist->head != NULL)
plist->head->prev = temp;**
temp->prev = NULL;
plist->head = temp;
(plist->numOfData)++;
}
#include <stdio.h>
#include <stdlib.h>
#include "Deque.h"
void DequeInit(Deque* pdeq)
{
pdeq->head = NULL;
pdeq->tail = NULL;
}
int DQIsEmpty(Deque* pdeq)
{
if (pdeq->head == NULL || pdeq->tail == NULL) // &&으로 할지, ||으로 할지 추후 결정 필요
return 1;
else
return 0;
}
void DQAddFirst(Deque* pdeq, Data data)
{
Node* tmpN = (Node*)malloc(sizeof(Node)); //임시 노드 생성
tmpN->data = data; //데이터 저장
if (pdeq->head == NULL)
{
pdeq->head = tmpN;//머리 할당
pdeq->tail = tmpN;//꼬리 할당
}
else
{
tmpN->next = pdeq->head; //새 노드에 머리 연결
pdeq->head->prev = tmpN; //머리에 새 노드 연결
pdeq->head = tmpN; //머리 이동
}
tmpN->prev = NULL;
}
void DQAddLast(Deque* pdeq, Data data)
{
Node* tmpN = (Node*)malloc(sizeof(Node)); //임시 노드 생성
tmpN->data = data; //데이터 저장
if (pdeq->tail == NULL)
{
pdeq->tail = tmpN;
pdeq->head = tmpN;
}
else
{
tmpN->prev = pdeq->tail;
pdeq->tail->next = tmpN;
pdeq->tail = tmpN;
}
}
Data DQRemoveFirst(Deque* pdeq)
{
if (pdeq->head == NULL)
{
printf("Memorry error!");
exit(-1);
}
Node* rNode = pdeq->head; //헤드 주소 백업
Data rdata = pdeq->head->data; //헤드 데이터 백업
if (pdeq->head == pdeq->tail)
{
pdeq->head = NULL;
}
else
pdeq->head = pdeq->head->next; //헤드 이동
free(rNode); //노드 메모리 할당 해제
return rdata;
}
Data DQRemoveLast(Deque* pdeq)
{
if (pdeq->tail == NULL)
{
printf("Memorry error!");
exit(-1);
}
Node* rNode = pdeq->tail; //꼬리 주소 백업
Data rdata = pdeq->tail->data; //꼬리 데이터 백업
if (pdeq->head == pdeq->tail)
{
pdeq->tail = NULL;
}
else
pdeq->tail = pdeq->tail->prev; //꼬리 이동
free(rNode); //노드 메모리 할당 해제
return rdata; //데이터 반환
}
Data DQGetFirst(Deque* pdeq)
{
if (pdeq->head == NULL)
{
printf("Memorry error!");
exit(-1);
}
Data rdata = pdeq->head->data;
return rdata;
}
Data DQGetLast(Deque* pdeq)
{
if (pdeq->tail == NULL)
{
printf("Memorry error!");
exit(-1);
}
Data rdata = pdeq->tail->data;
return rdata;
}
덱 소스코드이다.
#include <stdio.h>
#include "Deque.h"
int main(void)
{
// Deque의 생성 및 초기화 ///////
Deque deq;
DequeInit(&deq);
// 데이터 넣기 1차 ///////
DQAddFirst(&deq, 3);
DQAddFirst(&deq, 2);
DQAddFirst(&deq, 1);
DQAddLast(&deq, 4);
DQAddLast(&deq, 5);
DQAddLast(&deq, 6);
// 데이터 꺼내기 1차 ///////
while(!DQIsEmpty(&deq))
printf("%d ", DQRemoveFirst(&deq));
printf("\\n");
// 데이터 넣기 2차 ///////
DQAddFirst(&deq, 3);
DQAddFirst(&deq, 2);
DQAddFirst(&deq, 1);
DQAddLast(&deq, 4);
DQAddLast(&deq, 5);
DQAddLast(&deq, 6);
// 데이터 꺼내기 2차 ///////
while(!DQIsEmpty(&deq))
printf("%d ", DQRemoveLast(&deq));
return 0;
}
덱 메인
실행결과
책에서 나온 소스코드와 내 코드를 비교해보자. 코드를 짜면서도 간결하게 더 짤 수 있을 것 같다는 생각이 계속 들었다.
void DQAddFirst(Deque* pdeq, Data data)
{
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = pdeq->head; //첫 노드일 경우에는, next에 NULL 할당/두번째 이후부터는 새 노드와 헤드 연결
if (pdeq->head == NULL)
pdeq->tail = newNode; // 새 노드가 첫 노드일시 꼬리도 새 노드에 할당.
else
pdeq->head->prev = newNode; // 아닐경우, 헤드와 새 노드 연결
newNode->prev = NULL;
pdeq->head = newNode; //헤드 이동
}
강의에 나온 코드인데… 그냥 양뱡향때랑 거의 다른게 없다.
내 코드랑 비교해보면..
void DQAddFirst(Deque* pdeq, Data data)
{
Node* tmpN = (Node*)malloc(sizeof(Node)); //임시 노드 생성
tmpN->data = data; //데이터 저장
if (pdeq->head == NULL)
{
pdeq->head = tmpN;//머리 할당
pdeq->tail = tmpN;//꼬리 할당
}
else
{
tmpN->next = pdeq->head; //새 노드에 머리 연결
pdeq->head->prev = tmpN; //머리에 새 노드 연결
pdeq->head = tmpN; //머리 이동
}
tmpN->prev = NULL;
}
문장은 거의 비슷한데, 분기문에서 차이가 있다. 이건 사실 양뱡향 할때도 다뤘던 내용이다.
tmpN->next = pdeq->head; //새 노드에 머리 연결