2024년 7월 3일 수요일

자료구조 4강 연결리스트 두 번째 정리와 소스 코드

링크드리스트 시각화

배열을 이용한 데이터 저장 예제

코드 구현

#include <stdio.h>

int main() {
    int arr[10];
    int readCount = 0;
    int readData;
    int i;

    while(1)
    {
    printf("자연수 입력: ");
    scanf("%d", &readData);
    if(readData < 1)
    break;

    arr[readCount++] = readData;
    }

    for(i=0; i<readCount; i++)
    printf("%d ", arr[i]);

    return 0;
}

결과 출력

자연수 입력: 1
자연수 입력: 2
자연수 입력: 3
자연수 입력: 4
자연수 입력: 5
자연수 입력: 6
자연수 입력: 0
1 2 3 4 5 6


배열은 메모리의 특성이 정적이어서 메모리의 길이를 변경하는 것이 불가

다음 예제를 통해 동적 메모리 구성을 파악

코드 구현

#include <stdio.h>
#include <stdlib.h>

typedef struct _node
{
    int data;
    struct _node * next;
} Node;

int main() {
    Node * head = NULL;
    Node * tail = NULL;
    Node * cur = NULL;

    Node * newNode = NULL;
    int readData;

    while(1)
    {
        printf("자연수 입력: ");
        scanf("%d", &readData);
        if(readData < 1)
        break;

        // 노드의 추가과정
        newNode = (Node*)malloc(sizeof(Node));
        newNode->data = readData;
        newNode->next = NULL;

        if(head == NULL)
        	head = newNode;
        else
        	tail->next = newNode;

        tail = newNode;
	}
	printf("\n");

    printf("입력받은 데이터의 전체출력\n");
    if(head == NULL) {
    	printf("저장된 자연수가 존재하지 않습니다. \n");
    } else {
        cur = head;
        printf("%d ", cur->data);

        while(cur->next != NULL) {
            cur = cur->next;
            printf("%d ", cur->data);
        }
	}
    printf("\n\n");

    if(head == NULL)
        return 0;
    else {
        Node * delNode = head;
        Node * delNextNode = head->next;

        printf("%d을 삭제\n", head->data);
        free(delNode);

        while(delNextNode != NULL)
        {
            delNode = delNextNode;
            delNextNode = delNextNode->next;

            printf("%d을 삭제합니다. \n", delNode->data);
            free(delNode);
        }
    }

    return 0;
}

결과 출력

자연수 입력: 2
자연수 입력: 4
자연수 입력: 6
자연수 입력: 8
자연수 입력: 0
입력받은 데이터의 전체출력
2 4 6 8

2을 삭제
4을 삭제합니다.
6을 삭제합니다.
8을 삭제합니다.


위의 코드는 연결리스트의 ADT를 정의하지 않았고 삽입, 삭제, 조회 기능이 별도 함수로 구분되어 있지 않은 예제.

묶인 것이 아래의 예제이다. (여러 파일 구성)

코드 구현

// DLinkedList.h
#ifndef __D_LINKED_LIST_H__
#define __D_LINKED_LIST_H__

#define TRUE 1
#define FALSE 0

typedef int LData;

typedef struct _node
{
    LData data;
    struct _node* next;

} Node;

typedef struct _linkedList
{
    Node* head; // 연결 리스트의 머리를 가리키는 포인터 변수 -> 더미 노드를 가리키는 멤버
    Node* cur; // 참조를 위한 포인터 변수 -> 참조 및 삭제를 돕는 변수
    Node* before; // 삭제를 돕는 멤버

    int numOfData; // 저장된 데이터의 수를 기록하기 위한 멤버
    int (*comp)(LData d1, LData d2); // 정렬의 기준을 등록하기 위한 멤버

} LinkedList;

typedef LinkedList List;

void ListInit(List* plist);
void LInsert(List* plist, LData data);
void FInsert(List* plist, LData data);
void SInsert(List* plist, LData data);

int LFirst(List* plist, LData* pdata);
int LNext(List* plist, LData* pdata);

LData LRemove(List* plist);
int LCount(List* plist);

// 리스트 정렬에 기준이 되는 함수를 등록한다.
void SetSortRule(List* plist, int (*comp)(LData d1, LData dc2));

#endif

// DLinkedList.c
#include <stdio.h>
#include <stdlib.h>
#include "DLinkedList.h"

void ListInit(List* plist)
{
    plist->head = (Node*)malloc(sizeof(Node)); // 더미 노드 생성
    plist->head->next = NULL;
    plist->comp = NULL;
    plist->numOfData = 0;
}

void LInsert(List* plist, LData data)
{
	if(plist->comp == NULL)
	{
		FInsert(plist, data);
	}
	else
	{
		SInsert(plist, data);
	}
}

void FInsert(List* plist, LData data)
{
    Node* newNode = (Node*)malloc(sizeof(Node)); // 새 노드 생성
    newNode->data = data; // 새 노드에 데이터 저장

    newNode->next = plist->head->next; // 새 노드가 다른 노드를 가리키게 함
    plist->head->next = newNode; // 더미 노드가 새 노드를 가리키게 함

    plist->numOfData++; // 저장된 노드의 수 증가
}

void SInsert(List* plist, LData data)
{
    Node* newNode = (Node*)malloc(sizeof(Node)); // 새 노드 생성
    Node* pred = plist->head; // pred는 더미 노드를 가리킴
    newNode->data = data;

    // 새 노드가 들어갈 위치를 찾기 위한 반복문!
    while(pred->next != NULL && plist->comp(data, pred->next->data) != 0)
    {
    	pred = pred->next; // 다음 노드로 이동
    }

    newNode->next = pred->next; // 새 노드의 오른쪽을 연결
    pred->next = newNode; // 새 노드의 왼쪽을 연결

    plist->numOfData ++; // 저장된 노드의 수 증가
}

int LFirst(List* plist, LData* pdata) {
    if (plist->head->next == NULL) {
    	return FALSE;
	}

    plist->before = plist->head; // before는 더미 노드를 가리키게 함
    plist->cur = plist->head->next; // cur은 첫 번째 노드를 가리키게 함

    *pdata = plist->cur->data; // 첫 번째 노드의 데이터를 전달

    return TRUE;
}

int LNext(List* plist, LData* pdata)
{
    if(plist->cur->next == NULL)
    {
    	return FALSE;
    }

    plist->before = plist->cur; // cur이 가리키던 것을 before가 가리킴
    plist->cur = plist->cur->next; // cur은 그 다음 노드를 가리킴

    *pdata = plist->cur->data; // cur이 기리키는 노드의 데이터 전달

    return TRUE;
}

LData LRemove(List* plist)
{
    Node* rpos = plist->cur; // 소멸 대상의 주소 값을 rpos에 저장
    LData rdata = rpos->data; // 소멸 대상의 데이터를 rdata에 저장

    plist->before->next = plist->cur->next; // 소멸 대상을 리스트에서 제거
    plist->cur = plist->before; // cur이 가리키는 위치를 재조정

    free(rpos); // 리스트에서 제거된 노드 소멸
    plist->numOfData --; // 저장된 데이터의 수 하나 감소

    return rdata;
}

int LCount(List* plist)
{
	return plist->numOfData;
}

void SetSortRule(List* plist, int(*comp)(LData d1, LData d2))
{
	plist->comp = comp;
}
// DLinkedListMain.c
#include <stdio.h>
#include "DLinkedList.h"

int whoIsPrecede(int d1, int d2)
{
    if(d1 < d2)
    {
    	return 0;
    }

    return 1;
}

int main()
{
    List list;
    int data;
    ListInit(&list);

    SetSortRule(&list, whoIsPrecede);

    // 5개의 데이터 저장
    LInsert(&list, 1);
    LInsert(&list, 2);
    LInsert(&list, 3);
    LInsert(&list, 4);
    LInsert(&list, 5);

    // 저장된 데이터의 전체 출력
    printf("현재 데이터의 수: %d \n", LCount(&list));

    if(LFirst(&list, &data))
    {
        printf("%d ", data);

        while(LNext(&list, &data))
        {
        	printf("%d ", data);
        }
    }

    // 숫자 2를 검색하여 모두 삭제
    printf("현재 데이터의 수: %d \n", LCount(&list));

    if(LFirst(&list, &data))
    {
        if(data == 2)
        {
        	LRemove(&list);
        }

        while(LNext(&list, &data))
        {
            if(data == 2)
            {
            	LRemove(&list);
            }
        }
    }


    printf("현재 데이터의 수: %d \n", LCount(&list));

    if(LFirst(&list, &data))
    {
        printf("%d ", data);

        while(LNext(&list, &data))
        {
        	printf("%d ", data);
        }
    }
}

댓글 없음:

댓글 쓰기