PROWAREtech

articles » current » c-plus-plus » data-structures » heap

C++: Heap Data Structure

An O(log(n)) data structure.

Using Big O notation, add and remove data while sorting it at O(log(n)) speed which is very efficient. For best performance choose a min or max heap before adding data.

Written in C++ using templates.

#include <time.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <ctime>
using namespace std;

#define DEFAULT_SIZE 1000

unsigned int LeftChildIndex(const unsigned int index)
{
	return 2 * index + 1;
}

unsigned int RightChildIndex(const unsigned int index)
{
	return 2 * index + 2;
}

unsigned int ParentIndex(const int index)
{
	return (index - 1) / 2;
}

template <class TData> class HeapDataMembers
{
public:
	TData **items;
	unsigned int length, max;
	bool minheap;
	HeapDataMembers();
	HeapDataMembers(unsigned int arraySize);
	~HeapDataMembers();
	void DeleteLength();
};

template <class TData> class Heap
{
private:
	HeapDataMembers<TData> *dm;
	void RebuildMinHeap(const unsigned int index);
	void RebuildMaxHeap(const unsigned int index);
public:
	Heap();
	Heap(unsigned int arraySize);
	Heap(const Heap<TData> &obj);
	~Heap() { delete dm; }
	const Heap<TData> &operator=(const Heap<TData> &obj);
	unsigned int Length() const; // returns 0 when empty
	void MakeMinHeap(); // default is a min heap
	void MakeMaxHeap();
	void Add(const TData &data);
	bool Pop(TData &data); // returns false when there is no data
	const TData *Peek(); // peek at the data on the heap without popping it off
	void Clear();
};

template <class TData> HeapDataMembers<TData>::HeapDataMembers()
{
	max = DEFAULT_SIZE;
	length = 0;
	minheap = true;
	items = new TData*[max];
	for (unsigned int i = 0; i < max; items[i++] = nullptr);
}
template <class TData> HeapDataMembers<TData>::HeapDataMembers(unsigned int arraySize)
{
	max = arraySize;
	length = 0;
	minheap = true;
	if (max == 0)
		max = DEFAULT_SIZE;
	items = new TData*[max];
	for (unsigned int i = 0; i < max; items[i++] = nullptr);
}
template <class TData> HeapDataMembers<TData>::~HeapDataMembers()
{
	DeleteLength();
	if (items)
	{
		delete[]items;
		items = nullptr; // clean up the memory
	}
}
template <class TData> void HeapDataMembers<TData>::DeleteLength()
{
	if (items)
	{
		for (unsigned int i = 0; i < length; i++)
		{
			delete items[i];
			items[i] = nullptr; // clean up the memory
		}
	}
	length = 0;
}


template <class TData> Heap<TData>::Heap()
{
	dm = new HeapDataMembers<TData>();
}

template <class TData> Heap<TData>::Heap(unsigned int arraySize)
{
	dm = new HeapDataMembers<TData>(arraySize);
}

template <class TData> Heap<TData>::Heap(const Heap<TData> &obj)
{
	dm = new HeapDataMembers<TData>(1);
	this->operator=(obj);
}

template <class TData> const Heap<TData> &Heap<TData>::operator=(const Heap<TData> &obj)
{
	if (this != &obj)
	{
		Clear();
		dm->max = obj.dm->max;
		dm->length = obj.dm->length;
		dm->minheap = obj.dm->minheap;
		if (dm->items)
			delete[]dm->items;
		dm->items = new TData*[dm->max];
		unsigned int i;
		for (i = 0; i < dm->length; i++)
		{
			dm->items[i] = new TData;
			*(dm->items[i]) = *(obj.dm->items[i]);
		}
		for (; i < dm->max; dm->items[i++] = nullptr);
	}
	return (*this);
}

template <class TData> void Heap<TData>::Add(const TData &data)
{
	if (dm->length == dm->max) // then increase size of array
	{
		dm->max <<= 1;
		TData **newArray = new TData*[dm->max];
		unsigned int i;
		for (i = 0; i < dm->length; i++)
			newArray[i] = dm->items[i];
		for (; i < dm->max; newArray[i++] = nullptr);
		for (i = 0; i < dm->length; dm->items[i++] = nullptr);
		delete[]dm->items;
		dm->items = newArray;
	}
	dm->items[dm->length] = new TData;
	*(dm->items[dm->length]) = data;
	unsigned int newidx = dm->length;
	if (dm->minheap)
	{
		while (newidx >= 0)
		{
			unsigned int parentidx = ParentIndex(newidx);
			if (*dm->items[newidx] >= *dm->items[parentidx])
				break;
			TData *temp = dm->items[newidx];
			dm->items[newidx] = dm->items[parentidx];
			dm->items[parentidx] = temp;
			newidx = parentidx;
		}
	}
	else
	{
		while (newidx >= 0)
		{
			unsigned int parentidx = ParentIndex(newidx);
			if (*dm->items[newidx] <= *dm->items[parentidx])
				break;
			TData *temp = dm->items[newidx];
			dm->items[newidx] = dm->items[parentidx];
			dm->items[parentidx] = temp;
			newidx = parentidx;
		}
	}
	dm->length++;
}

template <class TData> void Heap<TData>::RebuildMinHeap(const unsigned int index)
{
	const unsigned int leftidx = LeftChildIndex(index);
	if (leftidx < dm->length)
	{
		const unsigned int rightidx = RightChildIndex(index);
		unsigned int largeridx = rightidx; // this is an assumption
		if ((largeridx >= dm->length) || (*dm->items[leftidx] < *dm->items[rightidx])) // then assumption was wrong
			largeridx = leftidx;
		if (*dm->items[index] > *dm->items[largeridx])
		{
			// swap data
			TData *temp = dm->items[index];
			dm->items[index] = dm->items[largeridx];
			dm->items[largeridx] = temp;
			RebuildMinHeap(largeridx); // Transform the semiheap rooted at largeridx into a heap
		}
	}
}

template <class TData> void Heap<TData>::RebuildMaxHeap(const unsigned int index)
{
	const unsigned int leftidx = LeftChildIndex(index);
	if (leftidx < dm->length)
	{
		const unsigned int rightidx = RightChildIndex(index);
		unsigned int largeridx = rightidx; // this is an assumption
		if ((largeridx >= dm->length) || (*dm->items[leftidx] > *dm->items[rightidx])) // then assumption was wrong
			largeridx = leftidx;
		if (*dm->items[index] < *dm->items[largeridx])
		{
			// swap data
			TData *temp = dm->items[index];
			dm->items[index] = dm->items[largeridx];
			dm->items[largeridx] = temp;
			RebuildMaxHeap(largeridx); // Transform the semiheap rooted at largeridx into a heap
		}
	}
}

template <class TData> const TData *Heap<TData>::Peek()
{
	if (dm->length)
		return dm->items[0];
	return nullptr;
}

template <class TData> bool Heap<TData>::Pop(TData &data)
{
	if (dm->length)
	{
		data = *dm->items[0];
		delete dm->items[0];
		dm->length--;
		dm->items[0] = (dm->length ? dm->items[dm->length] : nullptr);
		dm->items[dm->length] = nullptr;
		if (dm->length > 1)
		{
			if(dm->minheap)
				RebuildMinHeap(0);
			else
				RebuildMaxHeap(0);
		}
		return true;
	}
	return false;
}

template <class TData> unsigned int Heap<TData>::Length() const
{
	return dm->length;
}

template <class TData> void Heap<TData>::MakeMinHeap()
{
	if (!dm->minheap)
	{
		dm->minheap = true;
		for (int index = dm->length / 2 - 1; index >= 0; index--)
			RebuildMinHeap(index);
	}
}

template <class TData> void Heap<TData>::MakeMaxHeap()
{
	if (dm->minheap)
	{
		dm->minheap = false;
		for (int index = dm->length / 2 - 1; index >= 0; index--)
			RebuildMaxHeap(index);
	}
}

template <class TData> void Heap<TData>::Clear()
{
	dm->DeleteLength();
}

int main()
{
	{
		Heap<int> h(3);
		int n = time(0);
		srand(n);
		for (int i = 0; i < 20; i++)
		{
			n = rand();
			cout << n << endl;
			h.Add(n);
		}
		cout << endl;
		while (h.Pop(n))
			cout << n << endl;
	}
	cout << endl;
	{
		Heap<string> h(3);
		string s;
		h.MakeMaxHeap();
		for (int i = 0; i < 20; i++)
		{
			char c[4] = { 0,0,0,0 };
			c[0] = c[1] = c[2] = (char)(rand() % 26) + 97;
			s = c;
			cout << s << endl;
			h.Add(s);
		}
		cout << endl;
		while (h.Pop(s))
			cout << s << endl;
	}
	return 0;
}

PROWAREtech

Hello there! How can I help you today?
Ask any question

PROWAREtech

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
ACCEPT REJECT