🙇‍♀️선형 자료구조


🪐선형 vs 비선형

  • 선형 구조는 자료를 순차적으로 나열한 상태
    • 배열
    • 연결 리스트
    • 스택 / 큐
  • 비선형 구조는 하나의 자료 뒤에 다수의 자료가 올 수 있는 형태
    • 트리
    • 그래프


🪐배열 vs 동적 배열 vs 연결 리스트

  • 배열
    • 사용할 방 개수를 고정해서 계약 (변경 불가)
    • 연속된 방으로 배정 받아 사용
    • 장점 : 연속된 방
    • 단점 : 방을 추가 / 축소 불가
  • 동적 배열
    • 사용할 방 개수를 유동적으로 계약 (변경 가능)
    • 연속된 방으로 배정 받아 사용
    • 장점 : 연속된 방, 유동적인 계약 (방 여유분 추가 예약으로 이사 횟수 최소화)
    • 단점 : 이사 비용이 크다, 중간 삽입 / 삭제가 비효율적
    • 동적 배열 할당 정책 : 여유분을 두고 예약 -> 이사 횟수를 최소화
  • 연결 리스트
    • 비연속 된 방
    • 장점 : 중간 삽입 / 삭제 이점
    • 단점 : N번째 방을 바로 찾을 수가 없음 (임의 접근 Random Access 불가)

임의 접근? => N번째 방이 몇 번 방인지 바로 찾을 수 있는지


🪐배열 만들기

template<typename T>
class Vector
{
public:
	Vector()
	{

	}

	~Vector()
	{

	}

	void push_back(const T& value)
	{
		if (_capacity == _size)
		{
			int newCapacity = static_cast<int>(_capacity * 1.5);
			if (newCapacity == _capacity)
				newCapacity++;

			reserve(newCapacity);
		}

		_data[_size] = value;

		_size++;
	}

	void reserve(int capacity)
	{
		if (capacity <= _capacity)
			return;

		_capacity = capacity;

		// 새로운 데이터 동적 할당
		T* newData = new T[_capacity];

		// 데이터 복사
		for (int i = 0; i < _size; i++)
		{
			newData[i] = _data[i];
		}

		// 기존 데이터 삭제
		if (_data)
			delete[] _data;

		_data = newData;
	}

	void clear()
	{
		if (_data)
		{
			delete[] _data;
			_data = new T[_capacity];

		}

		_size = 0;
	}

	T& operator[](const int value) { return _data[value]; }

	int size() { return _size; }
	int capacity() { return _capacity; }

private:
	T* _data = nullptr;
	int _size = 0;
	int _capacity = 0;
};


🪐연결 리스트 만들기

#include <iostream>
using namespace std;
#include <vector>
#include <list>

template<typename T>
class Node
{
public:
	Node() : _prev(nullptr), _next(nullptr), _data(T())
	{

	}

	Node(const T& value) : _prev(nullptr), _next(nullptr), _data(value)
	{

	}

private:
	Node*	_prev;
	Node*	_next;
	T		_data;
};

template<typename T>
class Iterator
{
public:
	Iterator() : _node(nullptr)
	{

	}

	Iterator(Node<T>* node) : _node(node)
	{

	}

	Iterator& operator++()
	{
		_node = _node->_next;
		return *this;
	}

	Iterator operator++(int)
	{
		Iterator<T> temp = *this;
		_node = _node->_next;
		return temp;
	}

	Iterator& operator--()
	{
		_node = _node->_prev;
		return *this;
	}

	Iterator operator--(int)
	{
		Iterator<T> temp = *this;
		_node = _node->_prev;
		return temp;
	}

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

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

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

private:
	Node<T>* _node;
};

template<typename T>
class List
{
public:

	List() : _size(0)
	{
		_head = new Node<T>();
		_tail = new Node<T>();
		_head->_next = _tail;
		_tail->_prev = _head;
	}

	~List()
	{
		while (_size > 0)
		{
			pop_back();

			delete _head;
			delete _tail;
		}
	}


	void push_back(const T& value)
	{
		AddNode(_tail, value);
	}

	void pop_back()
	{
		RemoveNode(_tail->_prev);
	}

private:

	Node<T>* AddNode(Node<T>* before, const T& value)
	{
		Node<T>* newNode = new Node<T>(value);
		Node<T>* prevNode = before->_prev;
	
		prevNode->_next = newNode;
		newNode->_prev = prevNode;

		newNode->_next = before;
		before->_prev = newNode;

		_size++;

		return newNode;
	}

	Node<T>* RemoveNode(Node<T>* node)
	{
		Node<T>* prevNode = node->_prev;
		Node<T>* nextNode = node->_next;

		prevNode->next = nextNode;
		nextNode->_prev = prevNode;

		delete node;

		_size--;

		return nextNode;
	}

	int size() { return _size; }

public:
	using iterator = Iterator<T>;

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

	iterator insert(iterator it, const T& value)
	{
		Node<T>* node = AddNode(it._node, value);
		return iterator(node);
	}

	iterator erase(iterator it)
	{
		Node<T>* node = RemoveNode(it._node);
		return iterator(node);
	}

public:
	Node<T>*	_head;
	Node<T>*	_tail;
	int			_size;
};