- 원형으로 순환되는 리스트
- 일반 연결리스트에서 마지막 노드가 nullptr이 아닌 첫번째 노드와 연결되는 리스트
- 원형 연결 리스트는 앞 뒤 구분이 없기 때문에 head를 기준으로 판별

🟥 head 는 항상 마지막 노드를 가리키고 있다!
🟥 head -> next = 첫번째 노드
-> 단방향 원형 연결 리스트
-> 양방향 원형 연결 리스트
이번 블로그에서는 단방향 원형 연결 리스트로 구현하였다
일반적인 노드 구조는 동일함
노드의 갯수를 나타낼 size 변수
노드안에 포함된 data값 & next 포인터
노드를 가리키는 head 포인터

자기 참조 구조체란?
-> 자기 자신의 자료형을 가리키는 포인터를 멤버로 가지는 구조체를 말한다
-> 여기서는 노드 구조체 안에 Node * next라고 하는 포인터가 있다
-> 구조체 노드 안에는 Node형을 가리키는 next포인터를 멤버로 갖고있다
template <typename T>
class CircleLinkedList
{
private:
int size;
struct Node
{
T data;
Node* next;
};
Node* head;
}
public:
// 생성자
CircleLinkedList()
{
size = 0;
head = nullptr;
}

head == nullptr이면 가리키고 있는 곳이 없다는 뜻 (노드가 비어있다)





// 앞에 값 넣기
void PushFront(T data)
{
Node* newnode = new Node;
newnode->data = data;
// 노드 하나도 없을때
if (head == nullptr)
{
head = newnode;
newnode->next = head;
}
else
{
newnode->next = head->next;
head->next = newnode;
// head 위치 그대로
}
size++;
}
PushFront와 코드는 거의 동일함
원형 연결 리스트는 앞과 뒤의 구분이 없기 때문에 head값을 기준으로 구분
head값의 위치를 옮겨주면 된다
// 뒤에 값 넣기
void PushBack(T data)
{
Node* newnode = new Node;
newnode->data = data;
// 노드 하나도 없을때
if (head == nullptr)
{
head = newnode;
newnode->next = head;
}
else
{
newnode->next = head->next;
head->next = newnode;
// head 위치 옮겨주기
head = newnode;
}
size++;
}






// 앞에 값 빼기
void PopFront()
{
if (head == nullptr)
{
cout << "Circle Linked List is Empty" << endl;
}
else
{
Node* deleteNode = head->next;
// 노드가 한개일때
if (head == head->next)
{
head = nullptr;
}
else
{
head->next = deleteNode->next;
}
delete deleteNode;
size--;
}
}
노드가 여러개의 경우




기존의 head 위치를 currentNode로 이동

deleteNode가 가리키고 있던 노드를 delete 삭제

최종적으로 노드가 3개 -> 2개로 변함

// 뒤에 값 빼기
void PopBack()
{
if (head == nullptr)
{
cout << "Circle Linked List is Empty" << endl;
}
else
{
// head의 이전노드 찾기
Node* currentNode = head;
Node* deleteNode = head;
if (head == head->next)
{
head = nullptr;
}
else
{
for (int i = 0; i < size - 1; i++)
{
currentNode = currentNode->next;
}
currentNode->next = head->next;
head = currentNode;
}
delete deleteNode;
size--;
}
}
void Show()
{
if (head != nullptr)
{
Node* currentNode = head->next;
for (int i = 0; i < size; i++)
{
cout << currentNode->data << " ";
currentNode = currentNode->next;
}
}
}
const int& Size()
{
return size;
}
~CircleLinkedList()
{
while (head != nullptr)
{
PopBack();
}
}
int main()
{
CircleLinkedList <int> circleLinkedList;
circleLinkedList.PushBack(10);
circleLinkedList.PushBack(20);
circleLinkedList.PushBack(30);
circleLinkedList.PushFront(5);
circleLinkedList.PushFront(1);
circleLinkedList.PopFront();
circleLinkedList.PopBack();
circleLinkedList.Show();
cout << endl << "size : " << circleLinkedList.Size() << endl;
return 0;
}
출력값 :
삽입/삭제 -> O(1)
-> 포인터가 자기 자신의 다음 노드를 알고있는 상태이기 때문에 삽입/삭제에 상수시간이 걸린다
탐색 -> O(n)
-> 원하는 요소에 접근하려면 노드가 N개 있을때 N번째 노드에 접근하고 싶을 경우, 포인터로 순차적으로 들어가야 하기 때문에 O(N)의 시간이 걸린다
(2024.12.12.목요일)