공부/Data Structure

Linked list 구현

sudo 2021. 8. 2. 02:05

Linkedlist.h (템플릿으로 구현해서 헤더파일에 구현까지 넣음)

#pragma once

template <typename T>
class CNode
{
// 생성자, 소멸자를 privated으로 두고 CLinkedlist를 friend로 선언해서
// 외부에선 생성못하고 CLinkedlist만 생성할 수 있도록 함
private:
	CNode() {}
	~CNode() {}

private:
	template <typename T>
	friend class CLinkedlist;

	template <typename T>
	friend class CIterator;

private:
	CNode<T>* m_Next;
	CNode<T>* m_Prev;
	T m_Data;
};

template <typename T>
class CIterator
{

private:
	template <typename T>
	friend class CLinkedlist;

public:
	CIterator()	:
		m_Node(nullptr)
	{
	}

	~CIterator()
	{

	}

private:
	CNode<T>* m_Node;

public:
	void operator ++ ()
	{
		m_Node = m_Node->m_Next;
	}

	void operator ++ (int)
	{
		m_Node = m_Node->m_Next;
	}

	void operator -- ()
	{
		m_Node = m_Node->m_Prev;
	}

	void operator -- (int)
	{
		m_Node = m_Node->m_Prev;
	}

	bool operator == (const CIterator<T>& iter) const
	{
		return m_Node == iter.m_Node;
	}

	bool operator != (const CIterator<T>& iter) const
	{
		return m_Node != iter.m_Node;
	}

	T& operator * ()	const
	{
		return m_Node->m_Data;
	}

};

template <typename T>
class CLinkedlist
{
public:
	CLinkedlist() 
	{
		m_Head = new NODE;
		m_Tail = new NODE;
		m_Head->m_Next = m_Tail;
		m_Tail->m_Prev = m_Head;

		m_Head->m_Prev = nullptr;
		m_Tail->m_Next = nullptr;
	}
	~CLinkedlist()
	{
		PNODE DeleteNode = m_Head;
		PNODE NextDeleteNode = DeleteNode->m_Next;

		while (DeleteNode)
		{
			delete DeleteNode;
			DeleteNode = NextDeleteNode;
			NextDeleteNode = NextDeleteNode->m_Next;
		}
	}

private:
	// 자주 사용하는 타입을 typedef으로 재정의
	typedef CNode<T>* PNODE;
	typedef CNode<T> NODE;

	// main에서도 쓸 수 있어야하니 public으로
public:
	typedef CIterator<T> iterator;

private:
	// Head를 의미하는 더미노드
	PNODE m_Head;
	// Tail을 의미하는 더미노드
	PNODE m_Tail;
	// 더미노드를 제외한 노드 개수
	int m_Count;

public:
	int size() const
	{
		return m_Count;
	}

	iterator GetHead() const
	{
		iterator iter;
		iter.m_Node = m_Head;
		return iter;
	}

	iterator GetTail() const
	{
		iterator iter;
		iter.m_Node = m_Tail;
		return iter;
	}

	iterator begin() const
	{
		iterator iter;
		iter.m_Node = m_Head->m_Next;
		return iter;
	}

	iterator end() const
	{
		iterator iter;
		iter.m_Node = m_Tail;
		return iter;
	}

	const T& back() const
	{
		iterator iter = end();
		--iter;
		return iter.m_Node->m_Data;
	}

	const T& front() const
	{
		iterator iter = begin();
		return iter.m_Node->m_Data;
	}

public:
	void push_back(const T& data)
	{
		PNODE NewNode = new NODE;
		NewNode->m_Data = data;

		// 원래 링크드 리스트의 가장 뒤 노드
		PNODE PushPrev = m_Tail->m_Prev;

		PushPrev->m_Next = NewNode;
		m_Tail->m_Prev = NewNode;

		NewNode->m_Next = m_Tail;
		NewNode->m_Prev = PushPrev;

		++m_Count;
	}
	
	void push_front(const T& data)
	{
		PNODE NewNode = new NODE;
		NewNode->m_Data = data;

		// 원래 링크드 리스트의 가장 앞에 노드
		PNODE PushNext = m_Head->m_Next;

		PushNext->m_Prev = NewNode;
		m_Head->m_Next = NewNode;

		NewNode->m_Prev = m_Head;
		NewNode->m_Next = PushNext;

		++m_Count;
	}

	void pop_back()
	{
		// pop_back할 노드가 없으면 바로 종료
		if (empty())
			return;

		PNODE DeleteNode = m_Tail->m_Prev;
		PNODE DeletePrev = DeleteNode->m_Prev;

		DeletePrev->m_Next = m_Tail;
		m_Tail->m_Prev = DeletePrev;

		DeleteNode->m_Next = nullptr;
		DeleteNode->m_Prev = nullptr;
		delete DeleteNode;

		--m_Count;
	}

	void pop_front()
	{
		// pop_back할 노드가 없으면 바로 종료
		if (empty())
			return;

		PNODE DeleteNode = m_Head->m_Next;
		PNODE DeleteNext = DeleteNode->m_Next;

		DeleteNext->m_Prev = m_Head;
		m_Head->m_Next = DeleteNext;

		DeleteNode->m_Next = nullptr;
		DeleteNode->m_Prev = nullptr;
		delete DeleteNode;

		--m_Count;
	}

	void clear()
	{
		if (empty())
			return;

		// m_Head, m_Tail을 제외하고 모든 노드를 삭제
		PNODE DeleteNode = m_Head->m_Next;
		PNODE NextNode = DeleteNode->m_Next;
		while (DeleteNode != GetTail().m_Node)
		{
			NextNode = DeleteNode->m_Next;
			delete DeleteNode;
			DeleteNode = NextNode;
		}
	}

	bool empty() const
	{
		return m_Count == 0;
	}

	// data를 갖고 있는 첫번째 노드의 iterator 리턴
	iterator find(const T& data)
	{
		iterator iter = begin();
		iterator iterEnd = end();

		for (; iter != iterEnd; ++iter)
		{
			if (*iter == data)
			{
				return iter;
			}
		}
		// 만약 없다면 end() 리턴
		return iterEnd;
	}

	// const T&로 인자타입을 설정해야한다.
	// 그렇게 해야 int num = 3; erase(num);처럼 lvalue를 인자타입으로 줄 수 있을 뿐만 아니라
	// erase(80)처럼 rvalue도 인자타입으로 줄 수 있다.
	iterator erase(const T& data)
	{
		iterator iter = find(data);

		if (iter == end())
			return iter;

		return erase(iter);
	}

	// 노드를 지우는 함수
	// 만약 없는 노드를 지우려고 하거나, 더미노드를 지우려고하면 tail노드 리턴
	// 정상적으로 지웠다면 지운 다음 노드를 리턴
	iterator erase(const iterator& iter)
	{
		if (iter == GetHead() || iter == GetTail())
			return GetTail();

		PNODE EraseNode = iter.m_Node;
		PNODE ErasePrev = EraseNode->m_Prev;
		PNODE EraseNext = EraseNode->m_Next;

		ErasePrev->m_Next = EraseNext;
		EraseNext->m_Prev = ErasePrev;

		delete EraseNode;

		--m_Count;

		iterator ret;
		ret.m_Node = EraseNext;
		return ret;
	}

	void sort(bool (*pFunc)(const T&, const T&))
	{
		iterator iter1 = begin();
		iterator iter1End = end();
		--iter1End;

		iterator iter2;
		iterator iter2End = end();

		for (; iter1 != iter1End; ++iter1)
		{
			iter2 = iter1;
			++iter2;
			for (; iter2 != iter2End; ++iter2)
			{
				if (pFunc(*iter1, *iter2))
				{
					T data = *iter1;
					*iter1 = *iter2;
					*iter2 = data;
				}
			}
		}
	}

};

main.cpp

#include <iostream>
#include "Linkedlist.h"
#include <time.h>
#include <vector>

// 오름차순 정렬을 위한 compare 함수
bool SortInt(const int& data1, const int& data2)
{
	return data1 > data2;
}

int main()
{
	srand((unsigned int)time(0));
	rand();

	//MyInt	Test = 100;
	CLinkedlist<int>  listInt;
	CLinkedlist<float>	listFloat;

	for (int i = 0; i < 100; ++i)
	{
		listInt.push_back(i + 1);
	}

	std::cout << listInt.back() << std::endl;
	std::cout << listInt.front() << std::endl;

	CLinkedlist<int>::iterator	iter;

	iter = listInt.erase(80);

	std::cout << "Delete Next Node Data : " << *iter << std::endl;

	int num = 1;
	iter = listInt.erase(num);

	std::cout << "Delete Next Node Data : " << *iter << std::endl;

	listInt.clear();

	for (int i = 0; i < 100; ++i)
	{
		listInt.push_back(rand() % 1000);
	}


	std::cout << "======= Before =======" << std::endl;
	for (iter = listInt.begin(); iter != listInt.end(); ++iter)
	{
		std::cout << *iter << std::endl;
	}

	listInt.sort(SortInt);

	std::cout << "======= After =======" << std::endl;
	for (iter = listInt.begin(); iter != listInt.end(); ++iter)
	{
		std::cout << *iter << std::endl;
	}



	return 0;
}

출력 결과를 보면 랜덤한 값을 넣은 링크드 리스트에 sort함수를 이용해서 오름차순으로 정렬까지 잘 되어 있음을 확인할 수 있다.