포트폴리오

c++ Doubly Linked List

윈우 2019. 10. 28. 06:23

스마트 포인터를 이용한 Doubly Linked List구현

#pragma once

#include <memory>

namespace lab10
{
	template<typename T>
	class Node
	{
	public:
		Node(std::unique_ptr<T> data);
		Node(std::unique_ptr<T> data, std::shared_ptr<Node<T>> prev);
		std::unique_ptr<T> Data;
		std::shared_ptr<Node<T>> Next;
		std::weak_ptr<Node<T>> Previous;

	};
	
	template<typename T>Node<T>::Node(std::unique_ptr<T> data)
		: Data(std::move(data))
	{
	}

	template<typename T>Node<T>::Node(std::unique_ptr<T> data, std::shared_ptr<Node<T>> prev)
		: Data(std::move(data))
		, Previous(prev)
	{
	}
}
#pragma once

#include <memory>
//#include<iostream>

namespace lab10
{
	template<typename T>
	class Node;

	template<typename T>
	class DoublyLinkedList
	{
	public:
		DoublyLinkedList();
		void Insert(std::unique_ptr<T> data);
		void Insert(std::unique_ptr<T> data, unsigned int index);
		bool Delete(const T& data);
		bool Search(const T& data) const;

		std::shared_ptr<Node<T>> operator[](unsigned int index) const;
		unsigned int GetLength() const;
	private:
		void insert(std::shared_ptr<Node<T>> node, std::unique_ptr<T> data);
		std::shared_ptr<Node<T>> getNodeByData(const T& data) const;
		std::shared_ptr<Node<T>> getNodeByIndex(unsigned int index) const;
		
		std::shared_ptr<Node<T>> mFirst;
		size_t mSize;
	};

	template<typename T>DoublyLinkedList<T>::DoublyLinkedList()
		: mFirst(nullptr)
		, mSize(0)
	{
	}

	template<typename T>
	void DoublyLinkedList<T>::Insert(std::unique_ptr<T> data)
	{
		Insert(std::move(data), mSize);
	}

	template<typename T>
	void DoublyLinkedList<T>::Insert(std::unique_ptr<T> data, unsigned int index)
	{
		if (mFirst == nullptr)
		{
			mFirst = std::make_shared<Node<T>>(std::move(data));
			mSize++;
			return;
		}

		std::shared_ptr<Node<T>> node = getNodeByIndex(index);
		if (node == nullptr)
		{
			// 해당 index에 node가 없으면 맨뒤에 추가한다.
			insert(getNodeByIndex(mSize - 1), std::move(data));
		}
		else
		{
			// 해당 index에 node가 있으면 node의 previous node 뒤에 붙여준다.
			insert(node->Previous.lock(), std::move(data));
		}
	}

	template<typename T>
	void DoublyLinkedList<T>::insert(std::shared_ptr<Node<T>> node, std::unique_ptr<T> data)
	{
		std::shared_ptr<Node<T>> newNode = std::make_shared<Node<T>>(std::move(data), node);
		mSize++;
		if (node == nullptr)
		{
			newNode->Next = mFirst;
			mFirst->Previous = newNode;
			mFirst = newNode;
			return;
		}

		if (node->Next != nullptr)
		{
			newNode->Next = node->Next;
			node->Next->Previous = newNode;
		}
		node->Next = newNode;
		newNode->Previous = node;
	}

	template<typename T>
	bool DoublyLinkedList<T>::Delete(const T& data)
	{
		std::shared_ptr<Node<T>> node = getNodeByData(data);
		if (node == nullptr)
			return false;

		std::shared_ptr<Node<T>> prevNode = node->Previous.lock();
		if (prevNode == nullptr)
		{
			node->Next->Previous.lock() = nullptr;
			mFirst = node->Next;
		}
		else
		{
			prevNode->Next = node->Next;

			if (node->Next != nullptr)
			{
				node->Next->Previous = node->Previous;
			}
		}
		--mSize;

		return true;
	}

	template<typename T>
	bool DoublyLinkedList<T>::Search(const T& data) const
	{
		if (getNodeByData(data) == nullptr)
			return false;

		return true;
	}
	
	template<typename T>
	std::shared_ptr<Node<T>> DoublyLinkedList<T>::getNodeByData(const T& data) const
	{
		if (mFirst == nullptr)
			return nullptr;

		std::shared_ptr<Node<T>> node = mFirst;
		while (node != nullptr)
		{
			if (*node->Data == data)
			{
				break;
			}

			node = node->Next;
		}
		return node;
	}

	template<typename T>
	std::shared_ptr<Node<T>> DoublyLinkedList<T>::getNodeByIndex(unsigned int index) const
	{
		if (index >= mSize)
			return nullptr;

		unsigned int i = 0;
		std::shared_ptr<Node<T>> node = mFirst;
		while (node != nullptr)
		{
			if (i == index)
			{
				break;
			}

			node = node->Next;
			i++;
		}
		return node;
	}

	template<typename T>
	std::shared_ptr<Node<T>> DoublyLinkedList<T>::operator[](unsigned int index) const
	{
		return getNodeByIndex(index);
	}

	template<typename T>
	unsigned int DoublyLinkedList<T>::GetLength() const
	{
		return mSize;
	}
}