Upload
jinojjan
View
348
Download
0
Embed Size (px)
Citation preview
연결 리스트
아꿈사 http://cafe.naver.com/architect1
박진호http://blog.naver.com/jinojjan
개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트
개요
일정한 순서를 가지는 데이터 요소들을 표현하는 방법 중의 하나
배열과 다르게 데이터 요소들의 논리적인 순서만 유지되고 기억 장소 내에서는 각 데이터 요소들은 논리적인 순서와는 상관없는 임의의 위치를 가지도록 하는 자료 구조
연결리스트에서는 각 데이터 요소들이 기억 장소 내의 어떤 위치에 어떤 항목이 있는지를 표시해 주어야 함 . 이를 위해 데이터 요소에는 데이터 값 , 위치 정보도 저장해 주어야 함 .
즉 , 배열에서의 단점을 제거하면서 메모리를 효율적으로 사용하고 삽입과 삭제 가 쉬워 처리 시간이 단축되나 , 관리 유지에 부가적 비용이 듦 .
개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트
사용 할 때
저장할 데이터 개수가 가변적 인 경우 배열은 설정된 크기를 넘어가면 데이터가 넘쳐서 실행 도중 프로그램 오류가 발생 배열에 설정된 크기가 변할 때마다 재 컴파일하는 것을 방지하려고 넉넉한 크기로 큰 배열을
만든다면 메모리 낭비가 발생 혹은 재 할 당 시 뒤로 한칸씩 밀고 중간에 값을 넣게되므로 속도 저하 list 를 사용하면 저장 공간의 크기가 자동으로 변하므로 유연하게 사용
중간에 데이터 삽입이나 삭제가 자주 일어날 경우 데이터를 랜덤하게 접근하는 경우가 많지 않을 경우
배열은 랜덤 접근이 가능하나 list 는 순차 접근만 가능
사용 하지 말아야 할 때
저장할 데이터 개수가 많으면서 검색을 자주 할 때 List 는 검색 속도가 느림 map 이나 set, hash_map 사용 아이템을 자주 사용하는 온라인 게임에서는 아이템 사용 시 아이템 정보에 빈번하게 접근하므로
성능을 위해 메모리 낭비를 감수하고 배열로 데이터를 저장해서 랜덤 접근을 사용 .
개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트
연결 리스트의 종류
단일 연결리스트 (singly linked list) 포인터를 이용해서 한 쪽 방향 으로만 연결되어 있는 구조
원형 ( 환형 ) 연결리스트 (circular linked list) 원형 ( 환형 ) 큐와 마찬가지로 마지막 노드에서 처음 노드로 연결하여 원형으로 된 구조
이중 연결리스트 (doubly linked list) 한 쪽 방향으로만 연결 된 경우 반대 방향의 노드를 접근하기 어렵다는 단점을 보안 , 양방향으로
포인터를 이용해서 연결한 구조
개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트
단일 연결리스트 (singly linked list)
구조가 간단하고 , 기억 장소의 소모가 적은 반면에 역방향으로 리스트를 검색할 수 없음 -> 노드를 삽입하거나 삭제하려면 별도의 포인터가 필요
위 단점을 해결하기 위해 이중 연결리스트 (doubly linlked list) 를 사용
기본 구조
A B C D
256 300 128 400
NULL
head
head->next
head->next->next->next
head->next->next
head->data
head->next-> data
head->next->next->data
< 연결리스트의 구조 >
기본 구조 ( 삽입 )
A B C D
256 300 128
400
NULL
head
head->next
head->next->next->next->next
head->next->next
head->data
head->next-> data
head->next->next->next->data
<삽입 >
F
head->next-?next-> data
head->next->next->next
기본 구조 ( 삭제 )
A B C D
256 300 128 400
NULL
head
head->next
head->datahead->next-> data
head->next->next
<삭제 >
개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트
원형 ( 환형 ) 연결리스트 (circular linked list)
맨 마지막 노드의 포인터를 NULL 로 하는 대신에 맨 앞의 노드에 연결시켜서 원형구조를 만든것 .
환영 연결리스트의 구조
< 원형 ( 환형 ) 연결리스트의 구조 >
A B C Dhead
개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트
이중 연결리스트 (doubly linked list)
노드가 양쪽 방향으로 연결되어 있는 리스트
이중 연결리스트의 구조오른쪽 방향 : rlink( 선행 노드 )왼쪽 방향 : llink( 후행 노드 )
< 이중연결리스트의 노드 구조 >
이중 연결리스트 장단점
단일 연결리스트는 오직 하나의 연결 부분 ( 링크필드 ) 을 가지고 있지만 , 이중연결 리스트는 연결부분을 두개로 하여 한 개일 때 보다는 기억장소의 낭비가 있지만 효율적인 리스트 운영이 가능
이중 연결리스트 동작
노드삽입
노드삭제
< 이중연결리스트의 노드 삽입 >
NULLNULL
headA B C D
X
< 이중연결리스트의 노드 삭제 >
NULLNULL
head A B C D
이중 연결리스트 소스#ifndef DOUBLY_LINKEDLIST_H#define DOUBLY_LINKEDLIST_H
#include <stdio.h>#include <stdlib.h>
typedef int ElementType;
typedef struct tagNode{
ElementType Data;struct tagNode* PrevNode;struct tagNode* NextNode;
} Node;
/* 함수원형선언*/Node* DLL_CreateNode( ElementType NewData );void DLL_DestroyNode( Node* Node);void DLL_AppendNode( Node** Head, Node* NewNode );void DLL_InsertAfter( Node* Current, Node* NewNode );void DLL_RemoveNode( Node** Head, Node* Remove );Node* DLL_GetNodeAt( Node* Head, int Location );int DLL_GetNodeCount( Node* Head );
#endif DOUBLY_LINKEDLIST_H
#ifndef LINKEDLIST_H#define LINKEDLIST_H
#include <stdio.h>#include <stdlib.h>
typedef int ElementType;
typedef struct tagNode{ElementType Data;struct tagNode* NextNode;} Node;
/* 함수원형선언*/Node* SLL_CreateNode(ElementType NewData);void SLL_DestroyNode(Node* Node);void SLL_AppendNode(Node** Head, Node* NewNode);void SLL_InsertAfter(Node* Current, Node* NewNode);void SLL_InsertNewHead(Node** Head, Node* New-Head);void SLL_RemoveNode(Node** Head, Node* Remove);Node* SLL_GetNodeAt(Node* Head, int Location);int SLL_GetNodeCount(Node* Head);
#endif
이중 연결리스트 소스 ( 생성 및 소멸 )
#include "DoubleList.h"
/* 노드생성 */Node* DLL_CreateNode( ElementType NewData ){
Node* NewNode = (Node*)malloc(sizeof(Node));
NewNode->Data = NewData;NewNode->PrevNode = NULL;NewNode->NextNode = NULL;
return NewNode;}
/* 노드소멸 */void DLL_DestroyNode( Node* Node ){
free(Node);}
#include "LinkedList.h“
/* 노드생성 */Node* SLL_CreateNode(ElementType NewData){
Node* NewNode = (Node*)malloc(sizeof(Node));
NewNode->Data = NewData; /* 데이터를저장한다 . */
NewNode->NextNode = NULL; /* 다음노드에대한포인터는 NULL 로초기화한다 . */
return NewNode;/* 노드의주소를반환한다 . */}
/* 노드소멸 */void SLL_DestroyNode(Node* Node){
free(Node);}
이중 연결리스트 소스 ( 추가 )
/* 노드추가 */void SLL_AppendNode(Node** Head, Node* NewNode){
/* 헤드노드가 NULL 이라면새로운노드가 Head */if ( (*Head) == NULL ) {
*Head = NewNode;} else{
/* 테일을찾아 NewNode를연결한다 . */
Node* Tail = (*Head);while ( Tail->NextNode != NULL
){
Tail = Tail->NextNode;
}
Tail->NextNode = NewNode;}
}
/* 노드추가 */void DLL_AppendNode( Node** Head, Node* NewNode ){
/* 헤드노드가 NULL 이라면새로운노드가 Head */if ( (*Head) == NULL ) {
*Head = NewNode;} else{
/* 테일을찾아 NewNode 를연결한다 . */Node* Tail = (*Head);while ( Tail->NextNode != NULL ){
Tail = Tail->NextNode;}
Tail->NextNode = NewNode;NewNode->PrevNode = Tail; /* 기존의테일을새로운테일의 PrevNode 가가리킨
다 . */}
}
NULL
NULL
headA B C DB
X
NULL
이중 연결리스트 소스 ( 삽입 )
/* 노드삽입 */void SLL_InsertAfter(Node* Current, Node* NewN-ode){
NewNode->NextNode = Current->NextNode;
Current->NextNode = NewNode;}
/* 노드삽입 */void DLL_InsertAfter( Node* Current, Node* NewNode ){
NewNode->NextNode = Current->NextNode;NewNode->PrevNode = Current;
if ( Current->NextNode != NULL ){
Current->NextNode->PrevNode = NewNode;
Current->NextNode = NewNode;}
}
NULLNULL
headA B C D
X
이중 연결리스트 소스 ( 제거 - 단일 )/* 노드제거 */void SLL_RemoveNode(Node** Head, Node* Remove){
if ( *Head == Remove ){
*Head = Remove->NextNode;}else{
Node* Current = *Head;while ( Current != NULL && Current->NextNode != Re-
move ){
Current = Current->NextNode;}
if ( Current != NULL )Current->NextNode = Remove->NextNode;
}}
이중 연결리스트 소스 ( 제거 - 이중 )/* 노드제거 */void DLL_RemoveNode( Node** Head, Node* Remove ){
if ( *Head == Remove ){
*Head = Remove->NextNode;if ( (*Head) != NULL )
(*Head)->PrevNode = NULL;
Remove->PrevNode = NULL;Remove->NextNode = NULL;
}else{
Node* Temp = Remove;
if ( Remove->PrevNode != NULL )Remove->PrevNode->NextNode = Temp-
>NextNode;
if ( Remove->NextNode != NULL )Remove->NextNode->PrevNode = Temp-
>PrevNode;
Remove->PrevNode = NULL;Remove->NextNode = NULL;
} }
NULLNULL
head A B C D
이중 연결리스트 소스 ( 탐색 )/* 노드탐색 */Node* SLL_GetNodeAt(Node* Head, int Location){
Node* Current = Head;
while ( Current != NULL && (--Loca-tion) >= 0)
{Current = Current-
>NextNode;}
return Current;}
/* 노드수세기 */int SLL_GetNodeCount(Node* Head){
int Count = 0;Node* Current = Head;
while ( Current != NULL ){
Current = Current->NextNode;
Count++;}
return Count;}
/* 노드탐색 */Node* DLL_GetNodeAt( Node* Head, int Location ){
Node* Current = Head;
while ( Current != NULL && (--Loca-tion) >= 0)
{Current = Current-
>NextNode;}
return Current;}
/* 노드수세기 */int DLL_GetNodeCount( Node* Head ){
unsigned int Count = 0;Node* Current = Head;
while ( Current != NULL ){
Current = Current->NextNode;
Count++;}
return Count;}
이중 연결리스트 소스 ( 출력 )void PrintNode( Node* _Node ){
if ( _Node->PrevNode == NULL )printf("Prev: NULL");
elseprintf("Prev: %d", _Node->PrevNode->Data);
printf(" Current: %d ", _Node->Data);
if ( _Node->NextNode == NULL )printf("Next: NULL\n");
elseprintf("Next: %d\n", _Node->NextNode->Data);
}
이중 연결리스트 소스 ( 메인 )int _tmain(int argc, _TCHAR* argv[]){
int i = 0;int Count = 0;Node* List = NULL;Node* NewNode = NULL;Node* Current = NULL;
/* 노드 5 개추가 */for ( i = 0; i<5; i++ ){
NewNode = DLL_CreateNode( i );DLL_AppendNode( &List, NewN-
ode );}
/* 리스트출력 */Count = DLL_GetNodeCount( List );for ( i = 0; i<Count; i++ ){
Current = DLL_GetNodeAt( List, i );
printf( "List[%d] : %d\n", i, Current->Data );
}
/* 리스트의세번째칸뒤에노드삽입 */printf( "\nInserting 3000 After [2]...\n\n" );
Current = DLL_GetNodeAt( List, 2 );NewNode = DLL_CreateNode( 3000 );DLL_InsertAfter( Current, NewNode );
/* 리스트출력 */Count = DLL_GetNodeCount( List );for ( i = 0; i<Count; i++ ){
Current = DLL_GetNodeAt( List, i );
printf( "List[%d] : %d\n", i, Current->Data );
}
/* 모든노드를메모리에서제거 */printf( "\nDestroying List...\n" );
Count = DLL_GetNodeCount(List);
for ( i = 0; i<Count; i++ ){
Current = DLL_GetNodeAt( List, 0 );
if ( Current != NULL ) {
DLL_RemoveNode( &List, Current );
DLL_DestroyNode( Current );
}}
return 0;}
연결 리스트감사합니다