프로그래밍 기초/자료구조

연결 자료구조 - 원형 연결 리스트(Circular Linked List)

niamdank 2020. 11. 11. 08:45

  원형 연결 리스트 

원형 연결 리스트는 마지막 노드가 처음 노드를 가리키는 환형 구조가 되는 연결 리스트로 단일 연결 리스트와 이중 연결 리스트에 모두 적용이 가능하다.

 

- 단일 연결 리스트 적용 예

 

- 이중 연결 리스트 적용 예

 

※ 리스트 순회 시 다음 노드가 첫 노드인 경우 순회를 종료하면 된다.

 

  원형 연결 리스트 구현 준비 

원형 연결 리스트는 단일 연결 리스트 혹은 이중 연결 리스트의 삽입과 삭제, 기능 연산에서 리스트의 끝을 확인하는 방식을 변경하여 구현할 수 있다.

 

단일 연결 리스트 혹은 이중 연결 리스트를 원형 연결 리스트로 변경하기 위해 다음의 메서드를 수정해야 한다.

 

  • 생성자
    • 복사 생성자
  • 메서드 
    • 데이터 삽입 메서드
    • 데이터 삭제 메서드
    • 기능 메서드

 

  단일 원형 연결 리스트 구현 

SinglyLinkedList를 변형하여 단일 원형 연결 리스트를 구현한다.

 

SinglyCircularLinkedList.h

#pragma once
#include <xutility>
#include <iostream>

struct SinglyCircularLinkedListNode
{
	SinglyCircularLinkedListNode() {}
	SinglyCircularLinkedListNode(int value) { m_data = value; }

	int m_data{ 0 };
	SinglyCircularLinkedListNode* m_next{ nullptr };
};

class SinglyCircularLinkedList
{
public:
#pragma region 생성자
	SinglyCircularLinkedList();
	SinglyCircularLinkedList(const SinglyCircularLinkedList& other);
	~SinglyCircularLinkedList();
#pragma endregion

#pragma region 속성
	const size_t Count() { return m_count; }
	SinglyCircularLinkedListNode& Front() { return *m_head; }
#pragma endregion

#pragma region 메서드
	void Add(int value);
	void Add(SinglyCircularLinkedListNode* node);
	void Insert(size_t index, int value);
	void Insert(size_t index, SinglyCircularLinkedListNode* node);

	bool Remove(int value);
	void Remove(const SinglyCircularLinkedListNode* node);
	void Clear();

	bool Contains(int value);
	bool Contains(const SinglyCircularLinkedListNode* node);
	SinglyCircularLinkedListNode* Find(int value);
	SinglyCircularLinkedListNode* FindLast(int value);
#pragma endregion

private:
#pragma region Class Util
	SinglyCircularLinkedListNode* PopNode(int value);
	void PushNode(SinglyCircularLinkedListNode* node);

	void UpdateHead(SinglyCircularLinkedListNode* node);
#pragma endregion
	
private:
#pragma region 변수
	size_t m_count;
	SinglyCircularLinkedListNode* m_head;
	SinglyCircularLinkedListNode* m_free;
#pragma endregion
};

 

생성자, 소멸자 구현

기본 생성자와 SinglyCircularLinkedList를 인자로 받는 복사 생성자를 구현한다.

 

SinglyCircularLinkedList.cpp

/// <summary>
/// 비어있는 SinglyCircularLinkedList를 생성한다.
/// </summary>
SinglyCircularLinkedList::SinglyCircularLinkedList()
	: m_count(0), m_head(nullptr), m_free(nullptr)
{
}

/// <summary>
/// 다른 SinglyCircularLinkedList가 가지고 있는 노드를 복사해 SinglyCircularLinkedList를 생성한다.
/// </summary>
/// <param name="other">기준이 될 SinglyCircularLinkedList</param>
SinglyCircularLinkedList::SinglyCircularLinkedList(const SinglyCircularLinkedList& other)
	: m_count(other.m_count), m_head(nullptr), m_free(nullptr)
{
	if (other.m_head == nullptr)
	{
		return;
	}

	SinglyCircularLinkedListNode* curNode{ other.m_head };
	SinglyCircularLinkedListNode* prevNode{ PopNode(curNode->m_data) };

	m_head = prevNode;
	curNode = curNode->m_next;

	while (curNode->m_next != other.m_head)
	{
		SinglyCircularLinkedListNode* newNode{ PopNode(curNode->m_data) };
		prevNode->m_next = newNode;
		prevNode = newNode;
		curNode = curNode->m_next;
	}
}

/// <summary>
/// 메모리 누수를 막기 위해 동적 생성한 노드들을 제거한다.
/// </summary>
SinglyCircularLinkedList::~SinglyCircularLinkedList()
{
	if (m_head != nullptr)
	{
		SinglyCircularLinkedListNode* head{ m_head };
		do
		{
			SinglyCircularLinkedListNode* curNode{ m_head };
			m_head = m_head->m_next;
			delete curNode;
		} while (m_head != head);
	}

	while (m_free != nullptr)
	{
		SinglyCircularLinkedListNode* curNode{ m_free };
		m_free = m_free->m_next;
		delete curNode;
	}
}

 

데이터 삽입 메서드 구현

데이터 삽입 연산에 필요한 메서드들을 구현한다.

 

SinglyCircularLinkedList.cpp

/// <summary>
/// SinglyCircularLinkedList의 시작 위치에 지정한 값이 포함된 새 노드를 추가한다.
/// </summary>
/// <param name="value">추가할 값</param>
void SinglyCircularLinkedList::Add(int value)
{
	SinglyCircularLinkedListNode* newNode{ PopNode(value) };
	Add(newNode);
}

/// <summary>
/// SinglyCircularLinkedList의 시작 위치에 지정한 노드를 추가한다.
/// </summary>
/// <param name="node">추가할 새 노드</param>
void SinglyCircularLinkedList::Add(SinglyCircularLinkedListNode* node)
{
	if (node == nullptr || node->m_next != nullptr)
	{
		throw std::invalid_argument("node");
	}

	node->m_next = m_head;

	UpdateHead(node);

	m_count++;
}

/// <summary>
/// SinglyCircularLinkedList의 지정한 인덱스에 해당하는 위치에 지정한 값이 포함된 새 노드를 추가한다.
/// </summary>
/// <param name="index">값을 추가할 인덱스</param>
/// <param name="value">추가할 값</param>
void SinglyCircularLinkedList::Insert(size_t index, int value)
{
	SinglyCircularLinkedListNode* newNode{ PopNode(value) };
	Insert(index, newNode);
}

/// <summary>
/// SinglyCircularLinkedList의 지정한 인덱스에 해당하는 위치에 지정된 노드를 추가한다.
/// </summary>
/// <param name="index">새 노드를 추가할 인덱스</param>
/// <param name="node">추가할 새 노드</param>
void SinglyCircularLinkedList::Insert(size_t index, SinglyCircularLinkedListNode* node)
{
	if (index > m_count)
	{
		throw std::out_of_range("index");
	}

	if (node == nullptr || node->m_next != nullptr)
	{
		throw std::invalid_argument("node");
	}

	SinglyCircularLinkedListNode* prevNode{ nullptr };
	SinglyCircularLinkedListNode* curNode{ m_head };
	while (index--)
	{
		prevNode = curNode;
		curNode = curNode->m_next;
	}

	node->m_next = curNode;

	if (prevNode != nullptr)
	{
		prevNode->m_next = node;
	}
	else
	{
		UpdateHead(node);
	}

	m_count++;
}

 

데이터 삭제 메서드 구현

데이터 삭제 연산에 필요한 메서드들을 구현한다.

 

SinglyCircularLinkedList.cpp

/// <summary>
/// SinglyCircularLinkedList에서 가장 처음 일치한 지정된 값을 포함한 노드를 제거한다.
/// </summary>
/// <param name="value">제거할 값</param>
bool SinglyCircularLinkedList::Remove(int value)
{
	if (m_head != nullptr)
	{
		SinglyCircularLinkedListNode* curNode{ m_head };
		do
		{
			if (curNode->m_data == value)
			{
				Remove(curNode);
				return true;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}

	return false;
}

/// <summary>
/// SinglyCircularLinkedList에서 지정된 노드를 제거한다.
/// </summary>
/// <param name="node">제거할 노드</param>
void SinglyCircularLinkedList::Remove(const SinglyCircularLinkedListNode* node)
{
	if (node == nullptr)
	{
		throw std::invalid_argument("node");
	}

	if (m_head != nullptr)
	{
		SinglyCircularLinkedListNode* prevNode{ nullptr };
		SinglyCircularLinkedListNode* curNode{ m_head };
		do
		{
			if (curNode == node)
			{
				if (prevNode != nullptr)
				{
					prevNode->m_next = curNode->m_next;
				}
				else
				{
					UpdateHead(curNode->m_next);
				}
				PushNode(curNode);
				m_count--;
				return;
			}
			prevNode = curNode;
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}

	throw std::out_of_range("node");
}

/// <summary>
/// SinglyCircularLinkedList의 모든 노드를 제거한다.
/// </summary>
void SinglyCircularLinkedList::Clear()
{
	if (m_head != nullptr)
	{
		SinglyCircularLinkedListNode* head{ m_head };
		do
		{
			SinglyCircularLinkedListNode* curNode{ m_head };
			m_head = m_head->m_next;
			PushNode(curNode);
		} while (m_head != head);
		m_head = nullptr;
	}
	m_count = 0;
}

 

기능 메서드 구현

자료구조를 효율적으로 사용하기 위한 기능 메서드를 구현한다.

 

SinglyCircularLinkedList.cpp

/// <summary>
/// 지정한 값을 포함한 노드가 존재하는지 확인한다.
/// </summary>
/// <param name="value">찾을 값</param>
/// <returns>값의 존재 여부</returns>
bool SinglyCircularLinkedList::Contains(int value)
{
	if (m_head != nullptr)
	{
		SinglyCircularLinkedListNode* curNode{ m_head };
		do
		{
			if (curNode->m_data == value)
			{
				return true;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}
	return false;
}

/// <summary>
/// 지정한 노드가 SinglyCircularLinkedList에 포함되는지 확인한다.
/// </summary>
/// <param name="node">찾을 노드</param>
/// <returns>노드의 포함 여부</returns>
bool SinglyCircularLinkedList::Contains(const SinglyCircularLinkedListNode* node)
{
	if (m_head != nullptr)
	{
		SinglyCircularLinkedListNode* curNode{ m_head };
		do
		{
			if (curNode == node)
			{
				return true;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}
	return false;
}

/// <summary>
/// 지정한 값을 포함하는 가장 처음 일치하는 노드를 반환한다.
/// </summary>
/// <param name="value">찾을 값</param>
/// <returns>지정한 값을 포함하는 노드(없는 경우: nullptr)</returns>
SinglyCircularLinkedListNode* SinglyCircularLinkedList::Find(int value)
{
	if (m_head != nullptr)
	{
		SinglyCircularLinkedListNode* curNode{ m_head };
		do
		{
			if (curNode->m_data == value)
			{
				return curNode;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}
	return nullptr;
}

/// <summary>
/// 지정한 값을 포함하는 가장 마지막 일치하는 노드를 반환한다.
/// </summary>
/// <param name="value">찾을 값</param>
/// <returns>지정한 값을 포함하는 노드(없는 경우: nullptr)</returns>
SinglyCircularLinkedListNode* SinglyCircularLinkedList::FindLast(int value)
{
	SinglyCircularLinkedListNode* matchNode{ nullptr };

	if (m_head != nullptr)
	{
		SinglyCircularLinkedListNode* curNode{ m_head };
		do
		{
			if (curNode->m_data == value)
			{
				matchNode = curNode;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}
	return matchNode;
}

 

  이중 원형 연결 리스트 구현 

DoublyLinkedList를 변형하여 이중 원형 연결 리스트를 구현한다.

 

DoublyCircularLinkedList.h

#pragma once
#include <xutility>
#include <iostream>

struct DoublyCircularLinkedListNode
{
	DoublyCircularLinkedListNode() {}
	DoublyCircularLinkedListNode(int value) { m_data = value; }

	int m_data{ 0 };
	DoublyCircularLinkedListNode* m_prev{ nullptr };
	DoublyCircularLinkedListNode* m_next{ nullptr };
};

class DoublyCircularLinkedList
{
public:
#pragma region 생성자
	DoublyCircularLinkedList();
	DoublyCircularLinkedList(const DoublyCircularLinkedList& other);
	~DoublyCircularLinkedList();
#pragma endregion

#pragma region 속성
	const size_t Count() { return m_count; }
	DoublyCircularLinkedListNode& First() { return *m_head; }
	DoublyCircularLinkedListNode& Last() { return *m_tail; }
#pragma endregion

#pragma region 메서드
	void AddFirst(int value);
	void AddFirst(DoublyCircularLinkedListNode* node);
	void AddLast(int value);
	void AddLast(DoublyCircularLinkedListNode* node);
	void Insert(size_t index, int value);
	void Insert(size_t index, DoublyCircularLinkedListNode* node);

	bool RemoveFirst(int value);
	bool RemoveLast(int value);
	void Remove(const DoublyCircularLinkedListNode* node);
	void Clear();

	bool Contains(int value);
	bool Contains(const DoublyCircularLinkedListNode* node);
	DoublyCircularLinkedListNode* Find(int value);
	DoublyCircularLinkedListNode* FindLast(int value);
#pragma endregion

private:
#pragma region Class Util
	DoublyCircularLinkedListNode* PopNode(int value);
	void PushNode(DoublyCircularLinkedListNode* node);
#pragma endregion
	
private:
#pragma region 변수
	size_t m_count;
	DoublyCircularLinkedListNode* m_head;
	DoublyCircularLinkedListNode* m_tail;
	DoublyCircularLinkedListNode* m_free;
#pragma endregion
};

 

생성자, 소멸자 구현

기본 생성자와 DoublyCircularLinkedList를 인자로 받는 복사 생성자를 구현한다.

 

DoublyCircularLinkedList.cpp

/// <summary>
/// 비어있는 DoublyCircularLinkedList를 생성한다.
/// </summary>
DoublyCircularLinkedList::DoublyCircularLinkedList()
	: m_count(0), m_head(nullptr), m_tail(nullptr), m_free(nullptr)
{
}

/// <summary>
/// 다른 DoublyCircularLinkedList가 가지고 있는 노드를 복사해 DoublyCircularLinkedList를 생성한다.
/// </summary>
/// <param name="other">기준이 될 DoublyCircularLinkedList</param>
DoublyCircularLinkedList::DoublyCircularLinkedList(const DoublyCircularLinkedList& other)
	: m_count(other.m_count), m_head(nullptr), m_tail(nullptr), m_free(nullptr)
{
	if (other.m_head == nullptr)
	{
		return;
	}

	DoublyCircularLinkedListNode* curNode{ other.m_head };

	m_head = m_tail = PopNode(curNode->m_data);
	curNode = curNode->m_next;

	while (curNode->m_prev != other.m_tail)
	{
		DoublyCircularLinkedListNode* newNode{ PopNode(curNode->m_data) };
		m_tail->m_next = newNode;
		newNode->m_prev = m_tail;
		m_tail = newNode;
		curNode = curNode->m_next;
	}

	m_head->m_prev = m_tail;
	m_tail->m_next = m_head;
}

/// <summary>
/// 메모리 누수를 막기 위해 동적 생성한 노드들을 제거한다.
/// </summary>
DoublyCircularLinkedList::~DoublyCircularLinkedList()
{
	if (m_head != nullptr)
	{
		DoublyCircularLinkedListNode* head{ m_head };
		do
		{
			DoublyCircularLinkedListNode* curNode{ m_head };
			m_head = m_head->m_next;
			delete curNode;
		} while (m_head != head);
	}

	while (m_free != nullptr)
	{
		DoublyCircularLinkedListNode* curNode{ m_free };
		m_free = m_free->m_next;
		delete curNode;
	}
}

 

데이터 삽입 메서드 구현

데이터 삽입 연산에 필요한 메서드들을 구현한다.

 

DoublyCircularLinkedList.cpp

/// <summary>
/// DoublyCircularLinkedList의 시작 위치에 지정한 값이 포함된 새 노드를 추가한다.
/// </summary>
/// <param name="value">추가할 값</param>
void DoublyCircularLinkedList::AddFirst(int value)
{
	DoublyCircularLinkedListNode* newNode{ PopNode(value) };
	AddFirst(newNode);
}

/// <summary>
/// DoublyCircularLinkedList의 시작 위치에 지정한 노드를 추가한다.
/// </summary>
/// <param name="node">추가할 새 노드</param>
void DoublyCircularLinkedList::AddFirst(DoublyCircularLinkedListNode* node)
{
	if (node == nullptr || node->m_prev != nullptr || node->m_next != nullptr)
	{
		throw std::invalid_argument("node");
	}

	node->m_next = m_head;
	if (m_head != nullptr)
	{
		m_head->m_prev = node;
		m_head = node;
	}
	else
	{
		m_head = m_tail = node;
	}

	m_head->m_prev = m_tail;
	m_tail->m_next = m_head;

	m_count++;
}

/// <summary>
/// DoublyCircularLinkedList의 끝 위치에 지정한 값이 포함된 새 노드를 추가한다.
/// </summary>
/// <param name="value">추가할 값</param>
void DoublyCircularLinkedList::AddLast(int value)
{
	DoublyCircularLinkedListNode* newNode{ PopNode(value) };
	AddLast(newNode);
}

/// <summary>
/// DoublyCircularLinkedList의 끝 위치에 지정한 노드를 추가한다.
/// </summary>
/// <param name="node">추가할 새 노드</param>
void DoublyCircularLinkedList::AddLast(DoublyCircularLinkedListNode* node)
{
	if (node == nullptr || node->m_prev != nullptr || node->m_next != nullptr)
	{
		throw std::invalid_argument("node");
	}

	node->m_prev = m_tail;
	if (m_tail != nullptr)
	{
		m_tail->m_next = node;
		m_tail = node;
	}
	else
	{
		m_head = m_tail = node;
	}

	m_head->m_prev = m_tail;
	m_tail->m_next = m_head;

	m_count++;
}

/// <summary>
/// DoublyCircularLinkedList의 지정한 인덱스에 해당하는 위치에 지정한 값이 포함된 새 노드를 추가한다.
/// </summary>
/// <param name="index">값을 추가할 인덱스</param>
/// <param name="value">추가할 값</param>
void DoublyCircularLinkedList::Insert(size_t index, int value)
{
	DoublyCircularLinkedListNode* newNode{ PopNode(value) };
	Insert(index, newNode);
}

/// <summary>
/// DoublyCircularLinkedList의 지정한 인덱스에 해당하는 위치에 지정된 노드를 추가한다.
/// </summary>
/// <param name="index">새 노드를 추가할 인덱스</param>
/// <param name="node">추가할 새 노드</param>
void DoublyCircularLinkedList::Insert(size_t index, DoublyCircularLinkedListNode* node)
{
	if (index > m_count)
	{
		throw std::out_of_range("index");
	}

	if (node == nullptr || node->m_next != nullptr)
	{
		throw std::invalid_argument("node");
	}

	DoublyCircularLinkedListNode* curNode{ m_head };
	DoublyCircularLinkedListNode* prevNode{ m_tail };
	for (int i = 0; i < index; i++)
	{
		prevNode = curNode;
		curNode = curNode->m_next;
	}

	node->m_prev = prevNode;
	if (prevNode != nullptr)
	{
		prevNode->m_next = node;
	}
	node->m_next = curNode;
	if (curNode != nullptr)
	{
		curNode->m_prev = node;
	}

	if (index == 0)
	{
		m_head = node;
	}
	if (index == m_count)
	{
		m_tail = node;
	}

	m_count++;
}

 

데이터 삭제 메서드 구현

데이터 삭제 연산에 필요한 메서드들을 구현한다.

 

DoublyCircularLinkedList.cpp

/// <summary>
/// DoublyCircularLinkedList에서 가장 처음 일치한 지정된 값을 포함한 노드를 제거한다.
/// </summary>
/// <param name="value">제거할 값</param>
bool DoublyCircularLinkedList::RemoveFirst(int value)
{
	bool foundNode{ false };
	DoublyCircularLinkedListNode* curNode{ m_head };

	if (m_head != nullptr)
	{
		do
		{
			if (curNode->m_data == value)
			{
				foundNode = true;
				break;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}

	if (!foundNode)
	{
		return false;
	}

	Remove(curNode);

	return true;
}

/// <summary>
/// DoublyCircularLinkedList에서 가장 처음 일치한 지정된 값을 포함한 노드를 제거한다.
/// </summary>
/// <param name="value">제거할 값</param>
bool DoublyCircularLinkedList::RemoveLast(int value)
{
	bool foundNode{ false };
	DoublyCircularLinkedListNode* curNode{ m_tail };

	if (m_tail != nullptr)
	{
		do
		{
			if (curNode->m_data == value)
			{
				foundNode = true;
				break;
			}
			curNode = curNode->m_prev;
		} while (curNode != m_tail);
	}

	if (!foundNode)
	{
		return false;
	}

	Remove(curNode);

	return true;
}

/// <summary>
/// DoublyCircularLinkedList에서 지정된 노드를 제거한다.
/// </summary>
/// <param name="node">제거할 노드</param>
void DoublyCircularLinkedList::Remove(const DoublyCircularLinkedListNode* node)
{
	if (node == nullptr)
	{
		throw std::invalid_argument("node");
	}

	bool foundNode{ false };
	DoublyCircularLinkedListNode* curNode{ m_head };
	
	if (m_head != nullptr)
	{
		do
		{
			if (curNode == node)
			{
				foundNode = true;
				break;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}

	if (!foundNode)
	{
		throw std::out_of_range("node");
	}

	DoublyCircularLinkedListNode* prevNode{ curNode->m_prev };
	DoublyCircularLinkedListNode* nextNode{ curNode->m_next };
	prevNode->m_next = nextNode;
	if (prevNode == m_tail)
	{
		m_head = nextNode;
	}

	nextNode->m_prev = prevNode;
	if (nextNode == m_head)
	{
		m_tail = prevNode;
	}

	if (m_head == m_tail && m_tail == curNode)
	{
		m_head = m_tail = nullptr;
	}

	PushNode(curNode);

	m_count--;
}

/// <summary>
/// DoublyCircularLinkedList의 모든 노드를 제거한다.
/// </summary>
void DoublyCircularLinkedList::Clear()
{
	if (m_head != nullptr)
	{
		DoublyCircularLinkedListNode* head{ m_head };
		do
		{
			DoublyCircularLinkedListNode* curNode{ m_head };
			m_head = m_head->m_next;
			PushNode(curNode);
		} while (m_head != head);
	}
	m_head = m_tail = nullptr;
	m_count = 0;
}

 

기능 메서드 구현

자료구조를 효율적으로 사용하기 위한 기능 메서드를 구현한다.

 

DoublyCircularLinkedList.cpp

/// <summary>
/// 지정한 값을 포함한 노드가 존재하는지 확인한다.
/// </summary>
/// <param name="value">찾을 값</param>
/// <returns>값의 존재 여부</returns>
bool DoublyCircularLinkedList::Contains(int value)
{
	if (m_head != nullptr)
	{
		DoublyCircularLinkedListNode* curNode{ m_head };
		do
		{
			if (curNode->m_data == value)
			{
				return true;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}
	return false;
}

/// <summary>
/// 지정한 노드가 DoublyCircularLinkedList에 포함되는지 확인한다.
/// </summary>
/// <param name="node">찾을 노드</param>
/// <returns>노드의 포함 여부</returns>
bool DoublyCircularLinkedList::Contains(const DoublyCircularLinkedListNode* node)
{
	if (m_head != nullptr)
	{
		DoublyCircularLinkedListNode* curNode{ m_head };
		do
		{
			if (curNode == node)
			{
				return true;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}
	return false;
}

/// <summary>
/// 지정한 값을 포함하는 가장 처음 일치하는 노드를 반환한다.
/// </summary>
/// <param name="value">찾을 값</param>
/// <returns>지정한 값을 포함하는 노드(없는 경우: nullptr)</returns>
DoublyCircularLinkedListNode* DoublyCircularLinkedList::Find(int value)
{
	if (m_head != nullptr)
	{
		DoublyCircularLinkedListNode* curNode{ m_head };
		do
		{
			if (curNode->m_data == value)
			{
				return curNode;
			}
			curNode = curNode->m_next;
		} while (curNode != m_head);
	}
	return nullptr;
}

/// <summary>
/// 지정한 값을 포함하는 가장 마지막 일치하는 노드를 반환한다.
/// </summary>
/// <param name="value">찾을 값</param>
/// <returns>지정한 값을 포함하는 노드(없는 경우: nullptr)</returns>
DoublyCircularLinkedListNode* DoublyCircularLinkedList::FindLast(int value)
{
	if (m_tail != nullptr)
	{
		DoublyCircularLinkedListNode* curNode{ m_tail };
		do
		{
			if (curNode->m_data == value)
			{
				return curNode;
			}
			curNode = curNode->m_prev;
		} while (curNode != m_tail);
	}
	return nullptr;
}