일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 가상메모리
- DB
- 데이터분석
- 언어모델
- 스케줄러
- 소프트웨어공학
- 파싱
- 객체지향설계
- 데이터베이스
- 운영체제
- 836
- 오픈소스웹소프트웨어
- 웹소프트웨어
- 파싱테이블
- 정보검색
- 클래스
- 컴파일러
- Linear Algebra
- NLP
- C언어
- 컴파일
- OS
- Agile
- 벡터
- React
- 프로세스
- css
- 애자일
- 자연어처리
- 랩실일기
- Today
- Total
observe_db
[자료구조] 연결 리스트 (Linked Lists) 본문
단순 연결 리스트(Singly Linked Lists and Chains)
순차리스트의 특성
- 데이터 객체의 연속된 원소들이 일정 거리만큼 떨어져 저장
-(배열) a_i,j가 L_ij에 저장된다면, a_i,j+1은 L_ij+1에 저장
-(스택) 제일 위의 원소가
-(큐) 큐의 i번째 요소가 L_i에 위치하면 i+1 ->(L_i+1)%n
임의의 원소에 대한 삽입(Insertion)과 삭제(Deletion)에 많은 비용
- 중간에 하나의 삽입/삭제에 대해 다른 원소들의 이동이 필요하기 때문.
연결(linked) 표현
- 순차 표현에서 제기된 데이터 이동 문제점 해결
- 각 원소들이 메모리 내의 어떤 곳에나 위치 가능
- 원소에 정확한 순서로 접근하기 위한 정보가 필요(주소 정보)
노드(node)
- 0개 이상의 데이터 필드
- 1개 이상의 link 또는 pointer: 다음 원소를 가리킴
연결리스트의 일반적인 방법
- 노드들을 순차적으로 표시하고 링크를 화살표로 표현
- 화살표로 다음 노드를 직관적으로 가리킴
## !NOTE! ##
-노드들은 실제로 메모리 순차적 위치에 존재하지 않는다.
-노드들의 위치(주소)는 실행시마다 바뀔 수 있다. (malloc의 영향)
-link가 0(NULL)인지 검사하는 것 외에는 특정 주소 값을 찾지 않는다.
Insertion 과정
- 사용하지 않는 노드 하나를 가져온다
- 넣을 데이터를 노드의 데이터 필드에 넣고
- 넣을 위치의 앞 노드에 새 노드의 주소값을, 새 노드의 주소값에는 뒷 노드의 주소값을 넣는다.
(주소를 넣을 때에 앞 노드의 link 필드 값을 가져오는 방법도 있다.)
Deletion 과정
- 삭제할 노드의 앞 노드를 찾고
- link를 삭제할 노드의 다음 노드 주소로 수정한다.
C에서의 체인 표현(Representing chains in C)
노드 구조 (struct)
자기와 동일 타입에 대한 링크 (self-referential structure)
노드 생성시 메모리 할당 (malloc())
노드 메모리 해제 (free())
// 새로운 공백 리스트 생성
listPointer first = NULL;
// 공백 리스트인지 검사 매크로
#define IS_EMPTY(first)(!(first))
// 새로운 노드를 생성하기 위한 매크로 MALLOC
MALLOC(first, sizeof(*first)); //sizeof(*first) == 16byte
노드의 필드값 정의: -> 연산자 사용
예시) first->link = NULL;
또는) *(first).link = NULL;
+삽입과 삭제는 위와 동일하게.
삭제시에는 trail이라는 삭제할 노드의 선행노드를 가리키는 포인터를 사용.
연결 스택과 큐(Linked Stacks and Queues)
여러 개의 스택/큐가 동시에 있을 떄- 다중 스택과 큐를 순차적으로 표현할 때, 많은 오버헤드 발생
연결 스택과 큐
- 링크의 화살표 방향: 노드의 삽입과 삭제가 편리하게 만들어 줌
- (연결 스택) 톱에서 노드 삽입/삭제 용이
- (연결 큐) 뒤에선 노드를 쉽게 삽입, 앞에선 노드를 쉽게 삭제
연결 스택
#define MAX_STACKS 10 //스택 최대 수
typedef struct{
int key;
/* 기타 필드 */
} element;
typedef struct stack *stackPointer;
typedef struct stack {
element data;
stackPointer link;
};
stackPointer top[MAX_STACKS];
//PUSH
void push(int i, element item)
{
stackPointer temp;
MALLOC(temp, sizeof(*temp));
temp->data = item;
temp->link = top[i];
top[i] = temp;
}
//POP
void pop(int i)
{
stackPointer temp = top[i];
element item;
if(!temp) return stackEmpty();
item = temp->data;
top[i] = temp->link;
free(temp);
return item;
}
연결 큐
#define MAX_QUEUE 10 //큐의 최대 수
typedef struct queue *queuePointer;
typedef struct queue {
element data;
queuePointer link;
};
queuePointer front[MAX_QUEUES];
queuePointer rear[MAX_QUEUES];
// 큐 뒤에 삽입
void addq(i, item)
{
queuePointer temp;
MALLOC(temp, sizeof(*temp));
temp->data = item;
temp->link = NULL;
if(front[i]) rear[i]->link = temp;
else front[i] = temp;
rear[i] = temp;
}
// 앞에서부터 삭제
element eleteq(int i)
{
queuePointer temp = front[i];
element item;
if(!temp) return queueEmpty();
item = temp -> data;
front[i] = temp->link;
free(temp);
return item;
}
연결리스트로 n-stack/m-queue를 구현-> 구현의 단순함+Time Complexity의 감소.
: 추가공간을 위한 이동이 사라짐
가용 메모리가 남아있을 때까지 크기 증대 가능 (malloc())
링크에 대한 오버헤드가 발생하나, 장점이 많음.
: time 감소, space 증가
다항식(Polynomials)
리스트를 사용한 다항식 표현
- node: 계수, 지수, 포인터
- 계수는 정수라고 가정
typedef struct polyNOde *polyPointer;
typedef struct polyNode {
int coef;
int expon;
polyPointer link;
};
polyPointer a,b;
다항식 덧셈
a->expon과 b->expon을 비교
case1) 같은 경우
- 계수를 더하고
- 결과 다항식에 새로운 항을 만든후
- 둘다 다음 노드로 이동
case2) 한쪽이 큰 경우
- 큰 쪽과 같은 항을 만들어 결과 다항식에 첨가
- 큰 쪽을 다음 노드로 이동
세 가지 비용 요소
- 계수 덧셈
- 지수 비교
- 결과값을 위한 새로운 노드
다항식의 곱셈
a(x)*b(x)+d(x)이면
곱을 먼저 진행하여 임시 항(temp)를 만들고,
temp와 d(x)를 연산한 후, temp를 반환하여 메모리 가용도 높이기 가능.
다항식의 원형 리스트 표현
- 마지막 노드가 리스트의 첫 노드를 가리키도록 함.
- 해제된 노드를 체인 형태의 리스트로 유지
- 가용 공간 리스트 혹은 avail 리스트
- avail: 리스트에서 첫 번째 노드를 가리키는 포인터(초기값 NULL)
- 새로운 노드가 필요하면 이 리스트를 조사
- malloc, free 대신 getNode, retNode 사용
polyPointer getNOde(void)
{
polyPointer node;
if(avail){
node = avail;
avail = avail->link
}
else MALLOC(node, sizeof(*node));
return node;
}
void retNode(polyPointer node)
{
node->link = avail;
avail = node;
}
void cerase(polyPointer *ptr)
{
polyPointer temp;
if(*ptr) {
temp = (*ptr)->link;
(*ptr)->link = avail;
avail = temp;
*ptr = NULL;
}
}
제로 다항식
- 기존 방식으로는 제로 다항식에 별도 케이스를 만들어 처리
- 헤더 노드 사용하여 다항식 처리.(각 다항식은 헤더 노드를 갖도록 함)
추가 리스트 연산(Additional List Operation)
체인을 역순으로 만드는 (inverting, reversing) 연산
listPointer invert(listPointer lead)
{
listPointer middle, trail;
middle = NULL;
while (lead) {
// 리스트 첫 노드를 가리키는 lead를 옮겨가며 middle과 trail로 연결 수정
trail = middle;
middle = lead;
lead = lead->link; //미리 링크를 옮겨둠.(링크가 있을 때 이동)
middle->link = trail; //이부분이 핵심. 이전 노드(trail)을 현 노드(middle)의 link에 연결.
}
}
두 개의 체인 ptr1과 ptr2를 연결(concatenation)하는 연산
listPointer concatenate(listPointer ptr1, listPointer ptr2)
{
listPointer temp
// 둘 중 하나가 NULL이면 다른 리스트 리턴
if(!ptr1) return ptr2;
if(!ptr2) return ptr1;
// temp를 ptr1의 마지막 노드로 이동
for(temp = ptr1; temp->link; temp=temp->link) ;
temp->link = ptr2;
}
원형 연결 리스트에 삽입
리스트의 마지막 노드 포인터 last를 유지
void insertFront(listPointer *last, listPointer node)
{
// 리스트가 공백이면 last가 새로운 항목을 포인팅
if(IS_EMPTY(*first)){
*last = node;
node->link = node;
}
else {
node->link = (*last)->link;
(*last)->link = node;
}
}
// 길이 계산
int length(listPointer last)
{
listPointer temp;
int count = 0;
if (last) {
temp = last;
do{
count++;
temp = temp->link;
}while(temp != last);
}
}
희소행렬(Sparse Matrices)
- 희소행렬의 각 열과 행을 헤더 노드가 있는 원형 연결 리스트로 표현
- 각 노드에는 헤더노드와 엔트리 노드를 나타내기 위한 tag 필드 존재
헤더 노드(header)
- down: 열 리스트로 연결하는데 사용
- right: 행 리스트로 연결하는데 사용
- next: 헤드 노드들을 서로 연결하는데 사용
- 헤더 노드의 총 수: max{행의 수, 열의 수}
엔트리 노드(entry)
- tag 필드 외에 5개 필드(row, col, down, right, value)
- down: 같은 열에 있는 0이 아닌 다음 항 연결
- right: 같은 행에 있는 0이 아닌 다음 항 연결
필요한 노드 수
max{numRows, numCols} + numTems + 1
: 맨 앞항은 header 수, 뒤는 entry 수, 마지막 1은 header node list
#define MAX_SIZE 50 /* 최대 행렬 크기 */
typedef enum {head,entry} tagfield;
typedef struct matrixNode *matrixPointer;
typedef struct entryNode {
int row;
int col;
int value;
};
typedef struct matrixNode {
matrixPointer down;
matrixPointer right;
tagfield tag;
union {
matrixPointer next;
entryNode entry;
} u;
};
matrixPointer hdnode[MAX_SIZE];
입력을 할 때는 보조 배열 hdnode를 사용
- 적어도 입력될 행렬의 가장 큰 차원의 크기라고 가정
- 변수 hdnode[i]: 열 i와 행 i에 대한 헤더 노드를 가리키는 포인터
: 입력행렬을 구성하는 동안 임의의 열을 효과적으로 접근할 수 있게 함.
출력의 시간 복잡도: O(numRows+numTerms)
삭제의 시간 복잡도: O(numRows+numCols+numTerms)
이중 연결 리스트(Doubly Linked List)
- 포인터를 양방향으로 이동할 필요가 있을 떄
- 임의의 노드를 삭제해야 되는 문제에 적합
- 각 노드는 전방과 후방을 가리키는 두 개의 링크를 가짐
임의의 노드 ptr에 대해
ptr == ptr->llink->rlink == ptr->rlink->llink 성립
// insertion
void dinsert(nodePointer node, nodePointer newnode)
{
//node의 오른쪽에 newnode 삽입
newnode->llink = node;
newnode->rlink = node->rlink;
node->rrlink->llink = newnode;
node->rrlink = newnode;
}
//delete
void ddelete(nodePointer node, nodePointer deleted)
{
if(node == deleted) printf("NOT PERMITTED: Head Node Deletion");
else{
deleted->llink->rlink = deleted->rlink;
deleted->rlink->link = deleted->llink;
free(deleted);
}
}
'학교 공부 > 자구(2-1)' 카테고리의 다른 글
[자료구조] 힙(Heaps) (0) | 2025.01.06 |
---|---|
[자료구조] 트리(Trees) (0) | 2025.01.03 |
[자료구조] 스택과 큐(Stack and Queue) (0) | 2024.12.31 |
[자료구조] 배열과 구조(Array and Structure) (0) | 2024.12.24 |
[자료구조] 0. 들어가기 전에.. (0) | 2024.12.23 |