[Data Structure] 3. Circular List


特長

  • サイクル構造
  • ヘッダポインタと最後のノード上のpLinkは、第1のノード
  • を指す.
  • 要素の場合、第1ノードのpLinkは、自身(第1ノード)の
  • を指す.
  • 最初の位置にノードを追加する場合、最後のノードのpLink
  • を変更する必要がある.
  • の最初のノードを削除する場合はheadポインタを変更する必要があります
    -要素が1つしかない場合、ヘッダポインタはNULLを指します.
    -要素が1つの例外である場合、ヘッダポインタは現在の最初のノードのpLinkを指し、合計
  • .

    長所

  • 以外のヘッドの末尾ポインタがある場合は、ノードを先頭と末尾に簡単に追加できます.
  • 最後のノード=末尾、最初のノード=末尾のpLink、
  • にアクセス可能

    短所

  • 動的割当、ポインタ計算等は、
  • の実施・管理が困難である.
    検索
  • は、最初の要素からリンクに沿ってループする必要があるため、計算コストがより高い:O(n)
  • ポインタの使用は記憶空間
  • を浪費する.

    インプリメンテーション


    1. circularlist.c

    #include "circularlist.h"
    
    CircularList *createCircularList(void)
    {
    	CircularList *new;
    
    	new = calloc(1, sizeof(CircularList)); // 구조체 변수 (현재 원소 개수 - 0, headPtr - NULL) 초기화
    	if (!new)
    		return (NULL);
    	return (new);
    }
    
    //要素数==0(ノードを挿入するpLink=自身)

    //要素カウント>0&&挿入する位置==最初(最後のノードのpLink=挿入ノード)

    //要素数>0&&挿入する位置!=最初の
    int addCLElement(CircularList *pList, int position, ListNode element)
    {
    	ListNode	*new; // 삽입 노드
    	ListNode	*prev; // 삽입 노드를 연결 할 이전 노드
    	ListNode	*last; // 마지막 노드
    
    	if(!pList || position < 0 || position > pList->currentElementCount) // 에러 처리
    		return (FALSE);
    	new = malloc(sizeof(ListNode)); // 새 노드 할당
    	if (!new)
    		return (FALSE);
    	*new = element; // 정보 저장
    	prev = pList->headPtr;
    	if (position == 0) // 삽입하려는 위치가 첫번째일 경우
    	{
    		if (pList->currentElementCount == 0) // 현재 원소 개수가 0개일 때
    		{
    			new->pLink = new; // 삽입 노드의 pLink를 자기 자신으로
    			pList->headPtr = new; // headPtr의 pLink를 삽입 노드로
    		}
    		else // 현재 원소 개수가 1개 이상일 때
    		{
    			last = prev;
    			while (last->pLink != pList->headPtr) // 노드의 pLink가 headPtr이 가리키는 노드와 같을 경우 마지막 노드이므로 반복문 탈출
    				last = last->pLink; // 마지막 노드까지 last 이동
    			new->pLink = prev; // 삽입 노드의 pLink를 headPtr이 가리키고 있던 첫번째 노드에 연결
    			last->pLink = new; // 마지막 노드의 pLink를 삽입 노드에 연결
    			pList->headPtr = new; // headPtr을 삽입 노드에 연결
    		}
    	}
    	else // 삽입하려는 위치가 첫번째가 아닐 경우
    	{
    		while (--position > 0) // 삽입 위치 직전까지 prev 이동
    			prev = prev->pLink;
    		new->pLink = prev->pLink; // 삽입 노드의 pLink를 prev의 pLink에 연결
    		prev->pLink = new; // prev의 pLink에 삽입 노드를 연결
    	}
    	pList->currentElementCount++; // 현재 원소 개수 갱신
    	return (TRUE);
    }
    //要素数==1

    //要素数>1&ノード位置の削除!=最初の

    //元素数>1
    int removeCLElement(CircularList* pList, int position)
    {
    	ListNode *remove; // 제거 노드
    	ListNode *prev; // 제거 노드의 이전 노드
    	ListNode *last; // 마지막 노드
    
    	if (!pList || position >= pList->currentElementCount || position < 0) // 에러 처리
    		return (FALSE);
    	prev = pList->headPtr;
    	if (position == 0) // 제거 노드 위치가 첫번째일 경우
    	{
    		remove = prev; // 제거 노드 정보 저장
    		if (pList->currentElementCount == 1) // 현재 원소 개수가 1개일 때
    			pList->headPtr = NULL; // headPtr NULL에 연결
    		else // 현재 원소 개수가 1개 이상일 때
    		{
    			last = prev; // 마지막 노드
    			while (last->pLink != pList->headPtr) // 노드의 pLink가 headPtr이 가리키는 노드와 같을 경우 마지막 노드이므로 반복문 탈출
    				last = last->pLink; // 마지막 노드까지 last 이동
    			pList->headPtr = remove->pLink; // headPtr을 제거 노드의 pLink(현 두번째 노드)에 연결 
    			last->pLink = remove->pLink; // 마지막 노드의 pLink를 제거 노드의 pLink(현 두번째 노드)에 연결
    		}
    	}
    	else // 제거 노드 위치가 첫번째가 아닐 경우
    	{
    		while (--position > 0) // 제거 위치 직전까지 prev 이동
    			prev = prev->pLink;
    		remove = prev->pLink; // 제거 노드 정보 저장
    		prev->pLink = remove->pLink; prev의 pLink에 제거 노드의 pLink를 연결
    	}
    	free(remove); // 제거 노드 free
    	pList->currentElementCount--; // 현재 원소 개수 갱신
    	return (TRUE);
    }
    
    ListNode *getCLElement(CircularList *pList, int position)
    {
    	ListNode *ret;
    
    	if (!pList || position < 0 || position > pList->currentElementCount) // 에러 처리
    		return (FALSE);
    	ret = pList->headPtr; 
    	while (position-- > 0) // 반환 위치까지 ret 이동 
    		ret = ret->pLink;
    	return (ret);
    }
    
    int getCircularListLength(CircularList *pList)
    {
    	return (pList->currentElementCount);
    }
    
    void displayCircularList(CircularList *pList)
    {
    	ListNode	*cur;
    	int			i;
    
    	if (!pList) // 에러 처리
    	{
    		printf("No List\n");
    		return ;
    	}
    	printf("(1) Current Element count: %d\n", pList->currentElementCount);
    	if (pList->currentElementCount == 0)
    		printf("(2) Element: No Element\n\n");
    	else
    	{
    		printf("(2) Element\n");
    		cur = pList->headPtr;
    		for (i = 0; i < pList->currentElementCount; i++)
    		{
    			printf("[%d]: %d", i, cur->data);
    			if (i != pList->currentElementCount - 1)
    				printf(", "); // 마지막 노드 제외 쉼표 출력
    			cur = cur->pLink;
    		}
    		printf("\n\n");
    	}
    }
    
    void clearCircularList(CircularList* pList)
    {
    	ListNode* node;
    	ListNode* tmp;
    
    	if (pList->currentElementCount == 0)
    		return ;
    	node = pList->headPtr;
    	while (pList->currentElementCount-- > 0) // 현재 원소 개수만큼
    	{
    		tmp = node->pLink; 현재 노드의 다음 노드 저장을 위한 임시 변수 저장
            free(node); // 현재 노드 할당 해제
    		node = tmp; // 이전에 저장해 놓은 임시 변수 값을 가져와 연속적으로 리스트 순회
    	}
    	pList->headPtr = NULL; // 할당 해제 된 메모리에 접근하지 않도록 NULL처리
    	pList->currentElementCount = 0; // 현재 원소 개수 초기화
    }
    
    void deleteCircularList(CircularList *pList)
    {
    	clearCircularList(pList); // clear를 통해 리스트 내부 모든 노드 할당 해제
    	free(pList); // 리스트 구조체 할당 해제
    }

    2. circularlist_main.c

    #include "circularlist.h"
    
    int main(void)
    {
    	CircularList	*pList;
    	ListNode		*node;
    	ListNode		ListNode;
    	int				loop;
    	int				opt;
    	int				position;
    
    	pList = NULL;
    	while (loop)
    	{
    		printf("[1] Create [2] Add [3] Remove [4] Get Element [5] Length [6] Display [7] Clear [8] Delete [9] Exit ");
    		scanf("%d", &opt);
    		switch (opt)
    		{
    			case 1:
    				pList = createCircularList();
    				if (pList)
    					printf("Create Circular List: Success\n\n");
    				else
    					printf("Create Circular List: Failed\n\n");
    				break;
    			case 2:
    				printf("Position: ");
    				scanf("%d", &position);
    				printf("Data: ");
    				scanf("%d", &ListNode.data);
    				if (addCLElement(pList, position, ListNode))
    				{
    					printf("Add: Success\n\n");
    					displayCircularList(pList);
    				}
    				else
    					printf("Add: Failed\n\n");
    				break;
    			case 3:
    				printf("Position: ");
    				scanf("%d", &position);
    				if (removeCLElement(pList, position))
    				{
    					printf("Remove: Success\n\n");
    					displayCircularList(pList);
    				}
    				else
    					printf("Remove: Failed\n\n");
    				break;
    			case 4:
    				printf("Position: ");
    				scanf("%d", &position);
    				node = getCLElement(pList, position);
    				if (node)
    					printf("[%d]: %d\n\n", position, node->data);
    				else
    					printf("Failed\n\n");
    				break;
    			case 5:
    				printf("Length: %d\n\n", getCircularListLength(pList));
    				break;
    			case 6:
    				displayCircularList(pList);
    				break;
    			case 7:
    				if (!pList)
    					printf("Clear: Failed\n\n");
    				else
    				{
    					clearCircularList(pList);
    					printf("Clear: Success\n\n");
    				}
    				break;
    			case 8:
    				if (!pList)
    					printf("Delete: Failed\n\n");
    				else
    				{
    					deleteCircularList(pList);
    					pList = NULL;
    					printf("Delete: Success\n\n");
    				}
    				break;
    			case 9:
    				loop = 0;
    				break;
    			default:
    				printf("Please Enter a Valid Option\n\n");
    				break;
    		}
    	}
    }

    3. circularlist.h

    
    #ifndef _CIRCULARLIST_
    #define _CIRCULARLIST_
    
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct ListNodeType
    {
    	int data;
    	struct ListNodeType* pLink; // 다음 노드 연결을 위한 포인터
    } ListNode;
    
    typedef struct CircularListType
    {
    	int currentElementCount;	// 현재 저장된 원소의 개수
    	ListNode *headPtr;			// 헤드 포인터 
    } CircularList;
    
    CircularList* createCircularList();
    int addCLElement(CircularList* pList, int position, ListNode element);
    int removeCLElement(CircularList* pList, int position);
    ListNode* getCLElement(CircularList* pList, int position);
    int getCircularListLength(CircularList* pList);
    void displayCircularList(CircularList *pList);
    void clearCircularList(CircularList* pList);
    void deleteCircularList(CircularList* pList);
    #endif
    
    #ifndef _COMMON_LIST_DEF_
    #define _COMMON_LIST_DEF_
    
    #define TRUE		1
    #define FALSE		0
    
    #endif