Equivalent Relations

Equivalent Relation이란 symeetric, relfexive, transitive을 모두 다 만족하는 관계를 말합니다.

간단한 예시는 위와 같습니다. 이는 매우 중요한데, 그 이유는 equivalent relation이 signal net을 검증하기 때문입니다. equivalence를 결정하는 알고리즘은 아래와 같습니다.

2D array representation
위의 알고리즘을 구현하기 위해서는, 2차원 배열 pairs[n][m]이 사용되어야 합니다. 여기서 m은 related pairs의 개수고, n은 objects의 개수입니다. 하지만 이는 엄청난 공간 낭비를 할 수 있습니다. 그 이뉴능 아주 적은 배열의 값만이 사용될 수도 있기 때문입니다. 또한 <i, j> pair를 넣을 경우, i번째 행의 다음 공간을 찾을려면 많은 시간이 필요하기 때문입니다.

Linked List representation
또한 Linked List로 2D array로 구현하던걸 구현하면 불필요한 메모리의 낭비를 해결할 수 있습니다. 이를 해결하기 위해서는 두가지 배열을 사용해야 합니다. seq[n]과 out[n]입니다. 이의 역할을 아래와 같습니다.



결과적으로 우리는 위의 그림처럼 코드를 구상하여야 합니다.
equivalent-linked-list.c
#include <stdio.h> #include <stdlib.h> #define MALLOC(p, s) \ if (!((p) = malloc(s))) \ { \ fprintf(stderr, "Insufficient memory"); \ exit(EXIT_FAILURE); \ } #define REALLOC(p, s) \ if (!((p) = realloc(p, s))) \ { \ fprintf(stderr, "Insufficient memory"); \ exit(EXIT_FAILURE); \ } #define FALSE 0 #define TRUE 1 typedef struct node_ { int data; struct node_ *link; } node, *nodePointer; int main(void) { FILE *fp_read; if ((fp_read = fopen("input.txt", "r")) == NULL) { fprintf(stderr, "File Open Error!"); return 0; } int objectNumber, pairNumber, k; fscanf(fp_read, "%d", &objectNumber); fscanf(fp_read, "%d", &pairNumber); short *out; MALLOC(out, sizeof(short) * objectNumber); nodePointer *seq; MALLOC(seq, sizeof(nodePointer) * objectNumber); for (k = 0; k < objectNumber; k++) { out[k] = TRUE; } // 추가할 pair의 node nodePointer x; int i, j; for (k = 0; k < pairNumber; k++) { MALLOC(x, sizeof(node)); fscanf(fp_read, "%d %d", &i, &j); x->data = j; x->link = seq[i]; seq[i] = x; MALLOC(x, sizeof(node)); x->data = i; x->link = seq[j]; seq[j] = x; } nodePointer temp, temp2, top = NULL; for (i = 0; i < objectNumber; i++) { if (out[i] == TRUE) { if (i == 0) { printf("new class: %5d", i); } else { printf("\nnew class: %5d", i); } out[i] = FALSE; temp = seq[i]; while (TRUE) { while (temp) { j = temp->data; if (out[j]) { printf("%5d", j); out[j] = FALSE; temp2 = temp->link; temp->link = top; top = temp; temp = temp2; } else { temp = temp->link; } } if (!top) break; temp = seq[top->data]; top = top->link; } } } free(x); fclose(fp_read); return 0; }
input.txt
12 9 0 4 3 1 6 10 8 9 7 4 6 8 3 5 2 11 11 0

위의 그림에 있던 예제대로 코드를 짜고 동일한 equivalent-class끼리 출력을 했습니다.

알고리즘의 기본적인 형태는 위와 같고, 코드의 핵심은 top을 만들어서 노드를 하나씩 출력한 다음에 재귀적으로 계속 부르고 출력 한 것은 출력하지 않는 것입니다.
Equivalence Classes 총 정리


Sparse Matrices

linked-list로 sparse matrices를 나타내기 위해서는 Header Nodes와 Entry Nodes가 필요하다. 이를 구현하기 위해서는 2가지의 구조체와 공통된 부분을 위한 공용체가 필요하다.

이와같이 간단하게 구현할 수 있고 다음은 얘시 5*4 sparse matrix를 위 구조체와 공용체를 어떻게 구현할 수 있는지 보겠습니다.

보기 편하기 위해서 H0~H4를 2번 쓴것이고 그냥 2차원 배열을 쓰는 것처럼 down과 right의 matrixPoitner타입의 변수를 잘 활용해 주면 충분히 공간의 낭비없이 구현 가능합니다.
Doubly Linked Lists
Doubly Linked Lists는 기존의 linked-list와 다르게 양방향으로 움직일 수 있습니다. 이는 임의의 노드를 제거할 때 매우 유용하게 사용될 수 있는 자료형태 입니다. 각각의 노드는 최소한 3개의 필드를 가집니다. 형태는 아래와 같습니다.

이제 doubly-linked-list의 기본 연산함수에 대해서 살펴보도록 하겠습니다.
dinsert

dinsert의 기본 연산의 원리에 대해서 살펴보도록 하겠습니다. 일단 인자로는 삽입하기 전 node를 가리키는 포인터와, 삽입할 node포인터를 받습니다. 이제 삽입할노드를 newNode라고 하고 전노드를 node라고 합시다. 그럼 newnode->llink = node를 한 후, newnode->rlink = node-rlink를 하고, node->rlink->llink = newnode를 하고 마지막으로 node->rlink = newnode를 하면 newnode를 node후에 삽입하게 됩니다.
ddelete

ddelete의 기본 연산의 원리에 대해서 살펴보도록 하겠습니다. 일단 인자로는 headernode인 node와 삭제할 노드포인터인 deleted를 받게 됩니다. 그리고 deleted->llink->rlink = deleted->rlin를 하고 deleted->rlink->llink = deleted->llink를 한 후 마지막으로 free(deleted)로 해재해 주고 마지막으로 node가 deleted라면 에러 메세지를 띄우면 끝내면 됩니다. 그러면 성공적으로 deleted에 해당하는 노드가 삭제됩니다.
doubly-linked-list 총 정리

'School > DataStructure' 카테고리의 다른 글
Data-Structure - Arrays and Structure (0) | 2022.04.16 |
---|---|
Data-Structure - Tree (0) | 2022.04.14 |
Data-Structure - Linked-List( Application - 2 ) (0) | 2022.04.08 |
Data-Structure - Linked list ( Applications ) (0) | 2022.04.05 |
Data-Structure - Linked Lists (0) | 2022.04.01 |