inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

인프런 워밍업 클럽 4기 CS 전공지식 2주차 발자국

H_dong
0

[컴퓨터 구조]

멀티플렉서 (Multiplexer, MUX)

주요 역할: 다수의 데이터 중 필요한 것만 선택


디멀티플렉서 (Demultiplexer, DEMUX)

주요 역할: 하나의 데이터를 여러 대상 중 하나로 분배


디코더 (Decoder)

주요 역할: 특정 주소 또는 명령어를 구분해 선택


컨트롤 버퍼 (Control Buffer)

주요 역할:



반가산기 (Half Adder)

특징: 이전 자리에서의 올림값(Carry-in)을 처리할 수 없음


전가산기 (Full Adder)

특징: 자리올림 입력을 처리할 수 있어 다비트 덧셈 가능


조합 논리 회로 (Combinational Logic Circuit)

특징:

대표 예시:


순차 논리 회로 (Sequential Logic Circuit)

특징:

대표 예시:


SR 래치 (Set-Reset Latch)

image


D 래치 (Data or Delay Latch)

image


JK 래치

image


[자료구조와 알고리즘]

 

강의 수강

나의 주력 언어는 c++이라서 강의를 토대로 c++버젼으로 바꿔보았다


Red-Black Tree

 

Red-Black Tree의 주요 특징

 

Red-Black Tree의 장점

Red-Black Tree의 단점

 

시간 복잡도

Red_BlackTree.h

#pragma once
#include "BinarySearchTree.h"

// Red-Blakc Tree
// 1) 모든 노드는 Red or Black
// 2) Root는 Black
// 3) Leaf(NIL)는 Black
// 4) Red 노드의 자식은 Black (연속해서 Red-Red X)
// 5) 각 노드로부터 ~ 리프까지 가는 경로들은 모두 같은 수의 Black

class Red_BlackTree
{
public:
	Red_BlackTree();
	~Red_BlackTree();

	void Print();
	void Print(Node* node, int x, int y);

	Node* Search(Node* node, int key);

	Node* Min(Node* node);
	Node* Max(Node* node);
	Node* Next(Node* node);

	void	Insert(int key);
	void	InsertFixup(Node* node);

	void	Delete(int key);
	void	Delete(Node* node);
	void	DeleteFixup(Node* node);

	void	Replace(Node* u, Node* v);

	// Red-Black Tree
	void	RotateLeft(Node* node);
	void	RotateRight(Node* node);

private:
	Node* _root = nullptr;
	Node* _nil = nullptr;
};

Red_BlackTree.cpp

#include "Red_BlackTree.h"
#include <iostream>
#include <Windows.h>

using namespace std;

enum class ConsoleColor
{
	BlACK = 0,
	RED = FOREGROUND_RED,
	GREEN = FOREGROUND_GREEN,
	BLUE = FOREGROUND_BLUE,
	YELLOW = RED | GREEN,
	WHITE = RED | GREEN | BLUE,
};

void SetCursorColor(ConsoleColor color)
{
	HANDLE output = ::GetStdHandle(STD_OUTPUT_HANDLE);
	::SetConsoleTextAttribute(output, static_cast<SHORT>(color));
}

void SetCursorPosition(int x, int y)
{
	HANDLE output = ::GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
	::SetConsoleCursorPosition(output, pos);
}

void ShowConsoleCursor(bool flag)
{
	HANDLE output = ::GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO cursorInfo;
	::GetConsoleCursorInfo(output, &cursorInfo);
	cursorInfo.bVisible = flag;
	::SetConsoleCursorInfo(output, &cursorInfo);
}
Red_BlackTree::Red_BlackTree()
{
	_nil = new Node(); // Black
	_root = _nil;
	_root->parent = _nil;

}

Red_BlackTree::~Red_BlackTree()
{
	delete _nil;
}

void Red_BlackTree::Print()
{
	::system("cls");
	ShowConsoleCursor(false);
	Print(_root, 10, 0);
}

void Red_BlackTree::Print(Node* node, int x, int y)
{
	if (node == nullptr)
		return;

	SetCursorPosition(x, y);

	if (node->color == Color::Black)
		SetCursorColor(ConsoleColor::BLUE);
	else
		SetCursorColor(ConsoleColor::RED);

	cout << node->key;
	Print(node->left, x - (5 / (y + 1)), y + 1);
	Print(node->right, x + (5 / (y + 1)), y + 1);

	SetCursorColor(ConsoleColor::WHITE);
}


Node* Red_BlackTree::Search(Node* node, int key)
{
	if (node == _nil || key == node->key)
		return node;

	if (key < node->key)
		return Search(node->left, key);
	else
		return Search(node->right, key);
}

Node* Red_BlackTree::Min(Node* node)
{
	while (node->left != _nil)
		node = node->left;

	return node;
}

Node* Red_BlackTree::Max(Node* node)
{
	while (node->right != _nil)
		node = node->right;

	return node;
}

Node* Red_BlackTree::Next(Node* node)
{
	if (node->right != _nil)
		return Min(node->right);

	Node* parent = node->parent;

	while (parent != _nil && node == parent->right)
	{
		node = parent;
		parent = parent->parent;
	}

	return parent;
}

void Red_BlackTree::Insert(int key)
{ 
	Node* newNode = new Node();
	newNode->key = key;

	Node* node = _root;
	Node* parent = _nil;

	while (node != _nil)
	{
		parent = node;
		if (key < node->key)
			node = node->left;
		else
			node = node->right;
	}

	newNode->parent = parent;

	if (parent == _nil)
		_root = newNode;
	else if (key < parent->key)
		parent->left = newNode;
	else
		parent->right = newNode;

	// 검사
	newNode->left = _nil;
	newNode->right = _nil;
	newNode->color = Color::Red;

	InsertFixup(newNode);
}

void Red_BlackTree::InsertFixup(Node* node)
{
	// 1) p = red, uncle = red
	// -> p = black, uncle = black, pp = red로 바꿈
	// 2) p = red, uncle = black (triangle)
	// -> 회전을 통해 case 3으로 바꿈
	// 3) p = red, uncle = black (list)
	// -> 색상 변경 + 회전

	while (node->parent->color == Color::Red)
	{
		if (node->parent == node->parent->parent->left)
		{
			Node* uncle = node->parent->parent->right;
			if (uncle->color == Color::Red) // p = red, uncle = red
			{
				node->parent->color = Color::Black; // p
				uncle->color = Color::Black; // u
				node->parent->parent->color = Color::Red;
				node = node->parent->parent;
			}
			else // p = red, uncle = black
			{
				if (node == node->parent->right) 
				{
					// Triangle 타입
					//       [pp(B)]
					//   [p(R)]     [u(B)]
					//      [n(R)]

					//        [pp(B)]
					//      [p(R)]  [u(B)]
					//   [n(R)] 

					node = node->parent;
					RotateLeft(node);
				}

				// List 타입
				//        [pp(R)]
				//      [p(B)]  [u(B)]
				//   [n(R)]  

				//       [p(B)]  
				//   [n(R)]   [pp(R)]
				//					[u(B)]

				node->parent->color = Color::Black;
				node->parent->parent->color = Color::Red;
				RotateRight(node->parent->parent);
			}
		}

		else
		{
			Node* uncle = node->parent->parent->left;
			if (uncle->color == Color::Red) // p = red, uncle = red
			{
				node->parent->color = Color::Black; // p
				uncle->color = Color::Black; // u
				node->parent->parent->color = Color::Red;
				node = node->parent->parent;
			}
			else // p = red, uncle = black
			{
				if (node == node->parent->left)
				{
					node = node->parent;
					RotateRight(node);
				}

				// List 타입
				//					 [p(B)]    
				//			  [pp(R)]      [n(R)]  
				//      [u(B)]

				node->parent->color = Color::Black;
				node->parent->parent->color = Color::Red;
				RotateLeft(node->parent->parent);
			}
		}
	}

	_root->color = Color::Black;
}

void Red_BlackTree::Delete(int key)
{
	Node* deleteNode = Search(_root, key);
	Delete(deleteNode);
}

// 먼저 BST 삭제 실행
void Red_BlackTree::Delete(Node* node)
{
	if (node == _nil)
		return;

	if (node->left == _nil)
	{
		Color color = node->color;
		Node* right = node->right;

		Replace(node, node->right);

		if (color == Color::Black)
			DeleteFixup(right);
	}
	else if (node->right == _nil)
	{
		Color color = node->color;
		Node* left = node->left;

		Replace(node, node->left);

		if (color == Color::Black)
			DeleteFixup(left);
	}
	else
	{
		// 다음 데이터 찾기
		Node* next = Next(node);
		node->key = next->key;
		Delete(next);
	}
}

// 먼저 BST 삭제 실행...
// - Case 1) 삭제할 노드가 Red-> 그냥 삭제! 끝!
// - Case 2) root가 DB -> 그냥 추가 Black 삭제! 끝!
// - Case 3) DB의 sibling 노드가 Red
// -- s = black, p = red (s <-> p 색상 교환)
// -- DB 방향으로 rotate(p)
// -- goto other case
// - Case 4) DB의 sibling 노드가 Black && sibling의 양쪽 자식도 Black
// -- 추가 Black을 parent에게 이전
// --- p가 Red이면 Black 됨.
// --- p가 Black이면 DB 됨.
// -- s = red
// -- p를 대상으로 알고리즘 이어서 실행 (DB가 여전히 존재하면)
// - Case 5) DB의 sibling 노드가 Black && sibling의 near child = red, far child = black
// -- s <-> near 색상 교환
// -- far 방향으로 rotate(s)
// -- goto case 6
// - Case 6) DB의 sibling 노드가 Black && sibling의 far child = red
// - p <-> s 색상 교환
// - far = black
// - rotate(p) (DB 방향으로)
// - 추가 Black 제거
void Red_BlackTree::DeleteFixup(Node* node)
{
	Node* x = node;

	// [Case 1][Case 2]
	while (x != _root && x->color == Color::Black)
	{
		//			[p(B)]
		// [x(DB)]			[s(R)]
		//				[1]

		//			[S(B)]
		//		[p(R)]
		// [x[DB]	[1]

		if (x == x->parent->left)
		{
			Node* s = x->parent->right;
			// [Case 3]
			if (s->color == Color::Red)
			{
				s->color = Color::Black;
				x->parent->color = Color::Red;

				RotateLeft(x->parent);
				s = x->parent->right;
			}

			// [Case 4]
			if (s->left->color == Color::Black &&
				s->right->color == Color::Black)
			{
				s->color = Color::Red;
				x = x->parent;
			}
			else
			{
				// [Case 5]

				//			[p]
				// [x(DB)]		   [s(B)]
				//			 [near(R)] [far(B)]


				//			[p]
				// [x(DB)]		   [near(B)] 
				//						[s(R)]
				//							[far(B)]

				if (s->right->color == Color::Black)
				{
					s->left->color == Color::Black;
					s->color == Color::Red;
					RotateRight(s);
					s = x->parent->right;	// near
				}

				// [Case 6]

				//			[p]
				// [x(DB)]		   [s(B)] 
				//						[far(R)]

				s->color = x->parent->color;
				x->parent->color = Color::Black;
				s->right->color = Color::Black;
				RotateLeft(x->parent);
				x = _root; // 루프를 빠져나오기 위해서
			}
		}
		else
		{
			// [Case3]
			Node* s = x->parent->left;
			if (s->color == Color::Red)
			{
				s->color = Color::Black;
				x->parent->color = Color::Red;
				RotateRight(x->parent);
				s = x->parent->left; // [1]
			}

			// [Case4]
			if (s->right->color == Color::Black && s->left->color == Color::Black)
			{
				s->color = Color::Red;
				x = x->parent;
			}
			else
			{
				// [Case5]
				if (s->left->color == Color::Black)
				{
					s->right->color = Color::Black;
					s->color = Color::Red;
					RotateLeft(s);
					s = x->parent->left;
				}

				// [Case6]
				s->color = x->parent->color;
				x->parent->color = Color::Black;
				s->left->color = Color::Black;
				RotateRight(x->parent);
				x = _root;
			}
		}
	}
	x->color = Color::Black;
}

// u 서브트리를 v 서브트리로 교체
// 그리고 delete u
void Red_BlackTree::Replace(Node* u, Node* v)
{
	if (u->parent == _nil)
		_root = v;
	else if (u == u->parent->left)
		u->parent->left = v;
	else
		u->parent->right = v;

	v->parent = u->parent;

	delete u;
}

//    [x]  
// [1]   [y]
//      [2][3]

//     [y]
//  [x]   [3]
// [1][2]

void Red_BlackTree::RotateLeft(Node* x)
{
	Node* y = x->right;

	x->right = y->left;

	if (y->left != _nil)
		y->left->parent = x;

	y->parent = x->parent;

	if (x->parent == _nil)
		_root = y;
	else if (x == x->parent->left)
		x->parent->left = y;
	else
		x->parent->right = y;

	y->left = x;
	x->parent = y;
}

//     [y]
//  [x]   [3]
// [1][2]

//    [x]  
// [1]   [y]
//      [2][3]

void Red_BlackTree::RotateRight(Node* y)
{
	Node* x = y->left;

	y->left = x->right;

	if (x->right != _nil)
		x->right->parent = y;

	x->parent = y->parent;

	if (y->parent == _nil)
		_root = x;
	else if (y == y->parent->right)
		y->parent->right = x;
	else
		y->parent->left = x;

	x->right = y;
	y->parent = x;
}


출력 결과

int main()
{
	Red_BlackTree rbt;

	rbt.Insert(30);
	rbt.Print();
	//this_thread::sleep_for(1s);

	rbt.Insert(10);
	rbt.Print();
	//this_thread::sleep_for(1s);

	rbt.Insert(20);
	rbt.Print();
	//this_thread::sleep_for(1s);

	rbt.Insert(25);
	rbt.Print();
	//this_thread::sleep_for(1s);

	rbt.Insert(40);
	rbt.Print();
	//this_thread::sleep_for(1s);

	rbt.Insert(50);
	rbt.Print();
	//this_thread::sleep_for(1s);

	rbt.Delete(20);
	rbt.Print();
	this_thread::sleep_for(1s);

	rbt.Delete(10);
	rbt.Print();
	this_thread::sleep_for(1s);
}

image


우선순위 큐와 힙

우선순위 큐 (Priority Queue)

사용 예:

힙 (Heap)

시간복잡도

힙 정렬

동작 과정

  1. 배열을 힙 구조로 만든다 (heapify)

  2. 루트(최대/최소값)를 배열 끝으로 보내고 힙 크기 감소

  3. 나머지 트리를 다시 heapify

  4. 이 과정을 배열 전체 크기만큼 반복

시간 복잡도

PriorityQueue.h

#pragma once
#include <iostream>
#include <vector>

using namespace std;

template<typename T, typename Container = vector<T>, typename Predicate = less<T>>
class PriorityQueue
{
public:
	void push(const T& data)
	{
		// 우선 힙 구조부터 맞춰준다
		_heap.push_back(data);

		// 도장깨기 시작
		int now = static_cast<int>(_heap.size()) - 1;
		// 루트 노드까지
		while (now > 0)
		{
			// 부모 노드와 비교
			int next = (now - 1) / 2;
			if (_predicate(_heap[now], _heap[next]))
				break;

			// 데이터 교체
			::swap(_heap[now], _heap[next]);
			now = next;
		}
	}

	void pop() 
	{
		// 맨 뒤에값 루트로 교체 후 맨 뒤값 제거
		_heap[0] = _heap.back();
		_heap.pop_back();

		int now = 0;

		while (true)
		{
			int left = 2 * now + 1;
			int right = 2 * now + 2;

			// 리프에 도달한 경우
			if (left >= (int)_heap.size())
				break;

			int next = now;

			// 왼쪽과 비교
			if (_predicate(_heap[next], _heap[left]))
				next = left;
			
			// 둘 중 승자를 오른쪽과 비교
			if (right < (int)_heap.size() && _predicate(_heap[next], _heap[right]))
				next = right;

			// 왼쪽,오른쪽 둘 다 현재 값보다 작으면 종료
			if (next == now)
				break;

			::swap(_heap[now], _heap[next]);
			now = next;
		}
	}

	T& top()
	{
		return _heap[0];
	}

	bool empty()
	{
		return _heap.empty();
	}

private:
	Container _heap = {};
	Predicate _predicate = {};
};

 

출력 결과

int main()
{
	PriorityQueue<int, vector<int>, greater<int>> pq;
	//PriorityQueue<int, vector<int>> pq;

	pq.push(100);
	pq.push(300);
	pq.push(200);
	pq.push(500);
	pq.push(400);

	while (pq.empty() == false)
	{
		int value = pq.top();
		pq.pop();

		cout << value << endl;
	}
}

image

답변 0