Cod sursa(job #2451567)

Utilizator borcanirobertBorcani Robert borcanirobert Data 27 august 2019 11:53:24
Problema Sortare prin comparare Scor 60
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.85 kb
#include <iostream>
#include <fstream>
#include <cassert>

std::ifstream fin("algsort.in");
std::ofstream fout("algsort.out");

template<class T>
class RedBlackTree{
private:
	enum class Color{
		Red, Black
	};
	
	struct Node{
		Node* parent;
		Node* left;
		Node* right;
		Color color;
		T key;
	};
	
	// Helper functions
	Node* getParent(Node* n)
	{
		// The parent is going to be null if n is root node
		return n->parent;
	}
	
	Node* getGrandParent(Node* n)
	{
		Node* p = getParent(n);
		
		if (p == nullptr)		// no parent, no grandparent
			return nullptr;
		
		// The grandparent is going to be null if n is root node
		return getParent(p);
	}
	
	Node* getSibling(Node* n)
	{
		Node* p = getParent(n);
		
		if (p == nullptr)		// no parent, no sibling
			return nullptr;
		
		if (n == p->left)
			return p->right;
		return p->left;
	}
	
	Node* getUncle(Node* n)
	{
		Node* p = getParent(n);
		
		if (p == nullptr)		// no parent, no uncle
			return nullptr;
		
		return getSibling(p);
	}
	
	void rotateLeft(Node* n)
	{
		Node* p = getParent(n);
		Node* nnew = n->right;
		assert(nnew != nullptr);		// right son of n can't be null
		
		n->right = nnew->left;
		nnew->left = n;
		n->parent = nnew;
		if (n->right != nullptr)
			n->right->parent = n;
		
		if (p != nullptr)
		{
			if (n == p->left)
				p->left = nnew;
			else
				p->right = nnew;
		}
		
		nnew->parent = p;
	}
	
	void rotateRight(Node* n)
	{
		Node* p = getParent(n);
		Node* nnew = n->left;
		assert(nnew != nullptr);			// left son of n can't be null
		
		n->left = nnew->right;
		nnew->right = n;
		n->parent = nnew;
		if (n->left != nullptr)
			n->left->parent = n;
		
		if (p != nullptr)
		{
			if (n == p->left)
				p->left = nnew;
			else
				p->right = nnew;
		}
		
		nnew->parent = p;
	}
	
public:
	class iterator{
	public:
		iterator()
			: ptr{nullptr}
		{}
		
		iterator(const iterator& other)
			: ptr{new Node(other.ptr)}
		{}
		
		iterator(iterator&& other)
			: ptr{std::move(other.ptr)}
		{
			other.ptr = nullptr;
		}
		
		iterator(const Node& ptr)
			: ptr{new Node(ptr)}
		{}
	
		iterator& operator++()
		{
			if (ptr->right != nullptr)
			{
				ptr = ptr->right;
				
				while (ptr->left != nullptr)
					ptr = ptr->left;
				
				return *this;
			}
			
			while (ptr->parent != nullptr && 
					ptr->parent->right == ptr)
				ptr = ptr->parent;
			ptr = ptr->parent;
			return *this;	
		}
		
		T& operator *()
		{
			return ptr->key;
		}
		
		bool operator !=(const iterator& other) const
		{
			return ptr != other.ptr;
		}
		
		~iterator()
		{
			delete ptr;
		}
	private:
		Node* ptr;
	};

	RedBlackTree() : root{nullptr}
	{}

	void insert(const T& key)
	{
		Node* nnew = new Node;
		nnew->key = key;
		
		root = Insert(root, nnew);
	}
	
	void insert(T&& key)
	{
		Node* nnew = new Node;
		nnew->key = key;
		
		root = Insert(root, nnew);
	}
	
	iterator begin()
	{
		Node* node = new Node(*root);
		while (node->left != nullptr)
			node = node->left;
		
		return *node;
	}
	
	iterator end()
	{
		return iterator();
	}
	
	void WriteAll()
	{
		WriteAll(root);
	}
	
private:
	Node* root;
	
	void WriteAll(Node* n)
	{
		if (n == nullptr)
			return;

		WriteAll(n->left);
		std::cout << n->key << ' ';
		WriteAll(n->right);
	}

	Node* Insert(Node* root, Node* n)
	{
		// Insert the Node into the tree, just like you'd do
		// with a bynary search tree
		InsertRecurse(root, n);
		
		// And the repair the tree in case some rules
		// have been violated
		InsertRepairTree(n);
		
		root = n;
		while (getParent(root) != nullptr)
			root = getParent(root);
		
		return root;
	}
	
	void InsertRecurse(Node* root, Node* n)
	{
		if (root != nullptr && n->key < root->key)
		{
			if (root->left != nullptr)
			{
				InsertRecurse(root->left, n);
				return;
			}
			else
				root->left = n;
		}
		else if (root != nullptr)
		{
			if (root->right != nullptr)
			{
				InsertRecurse(root->right, n);
				return;
			}
			else
				root->right = n;
		}
		
		// Insert new Node n:
		n->parent = root;
		n->left = nullptr;
		n->right = nullptr;
		n->color = Color::Red;
	}
	
	void InsertRepairTree(Node* n)
	{
		if (getParent(n) == nullptr)
			InsertCase1(n);
		else if (getParent(n)->color == Color::Black)
			InsertCase2(n);
		else if (getUncle(n) != nullptr 
				&& getUncle(n)->color == Color::Red)
			InsertCase3(n);
		else
			InsertCase4(n);
	}
	
	void InsertCase1(Node* n)	// n is the root of the tree 
	{							// => we change its color to BLACK
		n->color = Color::Black;
	}
	
	void InsertCase2(Node* n)	// Cuurent node's parent is BLACK
	{							// => EVERY RULE is respected
	}
	
	void InsertCase3(Node* n)	// Both the parent and uncle are RED
	{
		// => Repaint parent, uncle and grandparent
		getParent(n)->color = Color::Black;
		getUncle(n)->color = Color::Black;
		getGrandParent(n)->color = Color::Red;
		
		// Now the grandparent could be violating rules
		// so we need to fix this by calling InsertRepairTree()
		// for the grandparent
		InsertRepairTree(getGrandParent(n));
	}
	
	void InsertCase4(Node* n)	// Parent is RED, Uncle is BLACK
	{
		Node* p = getParent(n);
		Node* g = getGrandParent(n);
		
		// First I make sure that n is "outside" of the subtree
		// under G (left of left of g or right of right of g)
		
		if (n == p->right && p == g->left)
		{
			rotateLeft(p);
			n = n->left;
		}
		else if (n == p->left && p == g->right)
		{
			rotateRight(p);
			n = n->right;
		}
		
		// And then I rotate in such a way that the parent
		// will be where the grandparent((will be turned to)BLACK)
		// was and will have as children the grandparent and
		// node n, (both (will be turned to) RED)
		p = getParent(n);
		g = getGrandParent(n);
		
		if (n == p->left)
			rotateRight(g);
		else
			rotateLeft(g);
		
		p->color = Color::Black;
		g->color = Color::Red;
	}
};

int main()
{
	RedBlackTree<int> rbt;
	
	int n, x;
	fin >> n;
	for (int i = 1; i <= n; ++i)
	{
		fin >> x;
		rbt.insert(x);
	}
	
	for (const int& v : rbt)
		fout << v << ' ';
	
	fin.close();
	fout.close();
	return 0;
}