알고리즘

Iterator를 지원하는 Double Linked List 구현

be_en 2025. 2. 24. 17:17
#include <iostream>

using namespace std;

//양방향 연결 리스트
template <typename T>
class DList
{
public:
	struct Node
	{
		T _data;
		Node* _next;
		Node* _prev;

		Node() : _data(T()), _next(nullptr), _prev(nullptr) {}
		Node(T data) : _data(data), _next(nullptr), _prev(nullptr) {}
	};

public:
	//양방향 이터레이터
	class Iterator
	{
	public:
		Iterator(Node* node = nullptr) : _node(node) {}
		
		Iterator& operator++()
		{
			if(_node != nullptr)
				_node = _node->_next;
			return *this;
		}
		const Iterator operator++(int)
		{
			Iterator temp = *this;
			if (_node != nullptr)
				_node = _node->_next;
			return temp;
		}
		Iterator& operator--()
		{
			if (_node != nullptr)
				_node = _node->_prev;
			return *this;
		}
		const Iterator operator--(int)
		{
			Iterator temp = *this;
			if (_node != nullptr)
				_node = _node->_prev;
			return temp;
		}

		T& operator*()
		{
			return _node->_data;
		}
		Node* operator->()
		{
			return _node;
		}

		bool operator==(const Iterator& other) const
		{
			return _node == other._node;
		}
		bool operator!=(const Iterator& other) const 
		{
			return _node != other._node;
		}

		Node* _node;
	};

public:
	//생성자
	DList()
		:_size(0), _head(nullptr), _tail(nullptr)
	{
		//더미를 둔다
		_head = new Node;
		_tail = new Node;

		_head->_next = _tail;
		_tail->_prev = _head;
	}

	//소멸자
	~DList()
	{
		while (_size > 0)
		{
			pop_front(); 
		}

		delete _head;
		delete _tail;
	}
	//뒤 삽입
	void push_back(const T& value)
	{
		//노드 생성
		Node* newNode = new Node(value);

		//노드 연결
		newNode->_prev = _tail->_prev;
		newNode->_next = _tail;
		_tail->_prev->_next = newNode;
		_tail->_prev = newNode;

		_size++;
	}
	//앞 삽입
	void push_front(const T& value)
	{
		//노드 생성
		Node* newNode = new Node(value);

		//노드 연결
		newNode->_next = _head->_next;
		newNode->_prev = _head;
		_head->_next->_prev = newNode;
		_head->_next = newNode;

		_size++;
	}
	//중간 삽입
	Iterator Insert(Iterator iter, const T& value)
	{
		//노드 생성
		Node* newNode = new Node(value);
		//iter가 가리키는 노드의 앞에 삽입한다.
		//노드 연결
		newNode->_next = iter._node;
		newNode->_prev = iter._node->_prev;
		iter._node->_prev->_next = newNode;
		iter._node->_prev = newNode;

		_size++;
		return Iterator(newNode);
	}
	
	//뒤 삭제
	void pop_back()
	{
		if (_size <= 0)
		{
			return;
		}

		Node* delNode = _tail->_prev;
		delNode->_prev->_next = _tail;
		_tail->_prev = delNode->_prev;

		delete delNode;

		_size--;
		return;
	}
	//앞 삭제
	void pop_front()
	{
		if (_size <= 0)
		{
			return;
		}

		Node* delNode = _head->_next;
		delNode->_next->_prev = _head;
		_head->_next = delNode->_next;

		delete delNode;

		_size--;
		return;
	}
	//중간 삭제
	Iterator erase(Iterator iter)
	{
		if (_size <= 0)
		{
			return Iterator(_tail);
		}

		//없앤 노드 다음 이터레이터를 반환해야 한다.
		Node* delNode = iter._node;
		Iterator delNextNodeIter = ++iter;
		delNode->_next->_prev = delNode->_prev;
		delNode->_prev->_next = delNode->_next;

		delete delNode;
		_size--;

		return delNextNodeIter;
	}
	
	//크기
	int GetSize() const
	{
		return _size;
	}

	Iterator begin()
	{
		return Iterator(_head->_next);
	}
	Iterator end()
	{
		return Iterator(_tail);
	}

private:
	Node* _head;
	Node* _tail;
	int _size;
};

 

헤드와 테일은 항상 더미노드를 가리키게 구현했다.

Iterator 패턴을 적용해서 raged-for에서도 활용 가능하다.

 

삽입 삭제를 구현할 때는 차분히 노드들의 앞 뒤 포인터의 변화를 생각하면 

구현할 수 있다.