29
연연 연연연 아아아 http://cafe.naver.com/architect1 아아아 http://blog.naver.com/jinojjan

연결리스트 박진호

Embed Size (px)

Citation preview

Page 1: 연결리스트 박진호

연결 리스트

아꿈사 http://cafe.naver.com/architect1

박진호http://blog.naver.com/jinojjan

Page 2: 연결리스트 박진호

개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트

Page 3: 연결리스트 박진호

개요

일정한 순서를 가지는 데이터 요소들을 표현하는 방법 중의 하나

배열과 다르게 데이터 요소들의 논리적인 순서만 유지되고 기억 장소 내에서는 각 데이터 요소들은 논리적인 순서와는 상관없는 임의의 위치를 가지도록 하는 자료 구조

연결리스트에서는 각 데이터 요소들이 기억 장소 내의 어떤 위치에 어떤 항목이 있는지를 표시해 주어야 함 . 이를 위해 데이터 요소에는 데이터 값 , 위치 정보도 저장해 주어야 함 .

즉 , 배열에서의 단점을 제거하면서 메모리를 효율적으로 사용하고 삽입과 삭제 가 쉬워 처리 시간이 단축되나 , 관리 유지에 부가적 비용이 듦 .

Page 4: 연결리스트 박진호

개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트

Page 5: 연결리스트 박진호

사용 할 때

저장할 데이터 개수가 가변적 인 경우 배열은 설정된 크기를 넘어가면 데이터가 넘쳐서 실행 도중 프로그램 오류가 발생 배열에 설정된 크기가 변할 때마다 재 컴파일하는 것을 방지하려고 넉넉한 크기로 큰 배열을

만든다면 메모리 낭비가 발생 혹은 재 할 당 시 뒤로 한칸씩 밀고 중간에 값을 넣게되므로 속도 저하 list 를 사용하면 저장 공간의 크기가 자동으로 변하므로 유연하게 사용

중간에 데이터 삽입이나 삭제가 자주 일어날 경우 데이터를 랜덤하게 접근하는 경우가 많지 않을 경우

배열은 랜덤 접근이 가능하나 list 는 순차 접근만 가능

Page 6: 연결리스트 박진호

사용 하지 말아야 할 때

저장할 데이터 개수가 많으면서 검색을 자주 할 때 List 는 검색 속도가 느림 map 이나 set, hash_map 사용 아이템을 자주 사용하는 온라인 게임에서는 아이템 사용 시 아이템 정보에 빈번하게 접근하므로

성능을 위해 메모리 낭비를 감수하고 배열로 데이터를 저장해서 랜덤 접근을 사용 .

Page 7: 연결리스트 박진호

개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트

Page 8: 연결리스트 박진호

연결 리스트의 종류

단일 연결리스트 (singly linked list) 포인터를 이용해서 한 쪽 방향 으로만 연결되어 있는 구조

원형 ( 환형 ) 연결리스트 (circular linked list) 원형 ( 환형 ) 큐와 마찬가지로 마지막 노드에서 처음 노드로 연결하여 원형으로 된 구조

이중 연결리스트 (doubly linked list) 한 쪽 방향으로만 연결 된 경우 반대 방향의 노드를 접근하기 어렵다는 단점을 보안 , 양방향으로

포인터를 이용해서 연결한 구조

Page 9: 연결리스트 박진호

개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트

Page 10: 연결리스트 박진호

단일 연결리스트 (singly linked list)

구조가 간단하고 , 기억 장소의 소모가 적은 반면에 역방향으로 리스트를 검색할 수 없음 -> 노드를 삽입하거나 삭제하려면 별도의 포인터가 필요

위 단점을 해결하기 위해 이중 연결리스트 (doubly linlked list) 를 사용

Page 11: 연결리스트 박진호

기본 구조

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

< 연결리스트의 구조 >

Page 12: 연결리스트 박진호

기본 구조 ( 삽입 )

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

Page 13: 연결리스트 박진호

기본 구조 ( 삭제 )

A B C D

256 300 128 400

NULL

head

head->next

head->datahead->next-> data

head->next->next

<삭제 >

Page 14: 연결리스트 박진호

개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트

Page 15: 연결리스트 박진호

원형 ( 환형 ) 연결리스트 (circular linked list)

맨 마지막 노드의 포인터를 NULL 로 하는 대신에 맨 앞의 노드에 연결시켜서 원형구조를 만든것 .

환영 연결리스트의 구조

< 원형 ( 환형 ) 연결리스트의 구조 >

A B C Dhead

Page 16: 연결리스트 박진호

개요사용 할 때 , 말아야 할 때연결리스트의 종류단일 연결 리스트원형 ( 환형 ) 연결 리스트이중 연결 리스트

Page 17: 연결리스트 박진호

이중 연결리스트 (doubly linked list)

노드가 양쪽 방향으로 연결되어 있는 리스트

이중 연결리스트의 구조오른쪽 방향 : rlink( 선행 노드 )왼쪽 방향 : llink( 후행 노드 )

< 이중연결리스트의 노드 구조 >

Page 18: 연결리스트 박진호

이중 연결리스트 장단점

단일 연결리스트는 오직 하나의 연결 부분 ( 링크필드 ) 을 가지고 있지만 , 이중연결 리스트는 연결부분을 두개로 하여 한 개일 때 보다는 기억장소의 낭비가 있지만 효율적인 리스트 운영이 가능

Page 19: 연결리스트 박진호

이중 연결리스트 동작

노드삽입

노드삭제

< 이중연결리스트의 노드 삽입 >

NULLNULL

headA B C D

X

< 이중연결리스트의 노드 삭제 >

NULLNULL

head A B C D

Page 20: 연결리스트 박진호

이중 연결리스트 소스#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

Page 21: 연결리스트 박진호

이중 연결리스트 소스 ( 생성 및 소멸 )

#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);}

Page 22: 연결리스트 박진호

이중 연결리스트 소스 ( 추가 )

/* 노드추가 */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

Page 23: 연결리스트 박진호

이중 연결리스트 소스 ( 삽입 )

/* 노드삽입 */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

Page 24: 연결리스트 박진호

이중 연결리스트 소스 ( 제거 - 단일 )/* 노드제거 */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;

}}

Page 25: 연결리스트 박진호

이중 연결리스트 소스 ( 제거 - 이중 )/* 노드제거 */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

Page 26: 연결리스트 박진호

이중 연결리스트 소스 ( 탐색 )/* 노드탐색 */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;}

Page 27: 연결리스트 박진호

이중 연결리스트 소스 ( 출력 )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);

}

Page 28: 연결리스트 박진호

이중 연결리스트 소스 ( 메인 )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;}

Page 29: 연결리스트 박진호

연결 리스트감사합니다