完全二叉树
首先让我们回顾一下完全二叉树的两个性质:
性质1:具有n个结点的完全二叉树的深度为[logn](向下取整)+1。
性质2:若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点:
(1) 若 i=1,则该结点是二叉树的根,无双亲,否则,编号为 [i/2](向下取整)的结点为其双亲结点;
(2) 若 2i>n,则该结点无左孩子,否则,编号为 2i 的结点为其左孩子结点;
(3) 若 2i+1>n,则该结点无右孩子结点,否则,编号为2i+1 的结点为其右孩子结点。
数组与完全二叉树
从上图可以看出, 如果完全二叉树从上到下且从左至右进行从0至n-1进行编号,则对完全二叉树的性质需要修改如下:
(1) 若 i=0,则该结点是二叉树的根,无双亲,否则,编号为 [(i-1)/2](向下取整)的结点为其双亲结点;
(2) 若 2i+1>n,则该结点无左孩子,否则,编号为 2i+1 的结点为其左孩子结点;
(3) 若 2i+2>n,则该结点无右孩子结点,否则,编号为2i+2 的结点为其右孩子结点。
大顶堆与小顶堆
堆是满足下列性质的数列{r1, r2, …,rn}:
(小顶堆)
(大顶堆)
大顶堆的设计
- template <typename Type>
- class MaxHeap
- {
- public:
- MaxHeap(int _maxSize = 10);
- virtual ~MaxHeap();
- bool isEmpty() const;
- void push(const Type &item);
- void pop();
- const Type &top() const;
- private:
- //将堆的容量增大两倍
- void resize();
- //向上渗透
- void trickUp(int index);
- //向下渗透
- void trickDown(int index);
- private:
- Type *heapArray;
- int maxSize;
- //currentSize有两个含义:
- // 1.代表当前堆中已经存储的元素数
- // 2.代表当前完全二叉树的第一个空位
- int currentSize;
- };
大顶堆的实现
- //构造
- template <typename Type>
- MaxHeap<Type>::MaxHeap(int _maxSize)
- : maxSize(_maxSize),currentSize(0)
- {
- if (maxSize < 1)
- throw std::length_error("heap size must >= 1");
- heapArray = new Type[maxSize];
- }
- //析构
- template <typename Type>
- MaxHeap<Type>::~MaxHeap()
- {
- delete []heapArray;
- heapArray = NULL;
- currentSize = 0;
- }
- //判空
- template <typename Type>
- bool MaxHeap<Type>::isEmpty() const
- {
- return currentSize == 0;
- }
堆顶元素
- //查看堆顶元素
- template <typename Type>
- const Type &MaxHeap<Type>::top() const
- {
- if (isEmpty())
- throw std::underflow_error("heap is empty");
- return heapArray[0];
- }
插入元素
- //插入
- template <typename Type>
- void MaxHeap<Type>::push(const Type &item)
- {
- //如果堆已满, 则需要对堆进行扩充
- if (currentSize == maxSize)
- {
- resize();
- }
- //将元素插入到堆的第一个空位置上
- heapArray[currentSize] = item;
- //维护堆的性质:向上渗透
- trickUp(currentSize);
- ++ currentSize;
- }
- //向上渗透, 将刚刚插入的元素移动到合适的位置上
- template <typename Type>
- void MaxHeap<Type>::trickUp(int index)
- {
- //根据完全二叉树的性质, 找到父节点
- int parent = (index-1)/2;
- Type bottom = heapArray[index];
- //循环终止条件
- // 1. index = 0 //bottom元素插入到根节点
- // 2. heapArray[parent] >= bottom //bottom插入到parent节点的一个子节点上
- while ((index > 0) && (heapArray[parent] < bottom))
- {
- //父节点下移
- heapArray[index] = heapArray[parent];
- index = parent;
- parent = (parent-1)/2;
- }
- //插入
- heapArray[index] = bottom;
- }
- //将堆的大小加倍
- template <typename Type>
- void MaxHeap<Type>::resize()
- {
- int newSize = std::max(maxSize*2, 1);
- Type *newHeap = new Type[newSize];
- for (int i = 0; i < currentSize; ++i)
- {
- newHeap[i] = heapArray[i];
- }
- delete []heapArray;
- heapArray = newHeap;
- maxSize = newSize;
- }
删除堆顶元素
- //删除
- template <typename Type>
- void MaxHeap<Type>::pop()
- {
- if (isEmpty())
- throw std::underflow_error("heap is empty");
- //只有一个元素
- if (currentSize == 1)
- {
- heapArray[0].~Type();
- currentSize = 0;
- return ;
- }
- //显示释放堆顶元素
- heapArray[0].~Type();
- //直接将最有一个元素放到堆顶,
- //并且currentSize-1
- heapArray[0] = heapArray[-- currentSize];
- //此时如果破坏了堆的性质:向下渗透
- trickDown(0);
- }
- //向下渗透
- template <typename Type>
- void MaxHeap<Type>::trickDown(int index)
- {
- int largeChild;
- Type top = heapArray[index];
- // 只需到达完全二叉树的最后一层
- // 的上一层即可
- // 循环的终止条件:
- // 1. index已经到达了最后一层(index >= currentSize/2 :找到了一个比较合适的位置)
- // 2. 在堆的中间找到了一个合适的位置(top >= heapArray[largeChild])
- while (index < currentSize/2)
- {
- int leftChild = (index*2)+1;
- int rightChild = leftChild + 1;
- //如果有右儿子节点, 而且右儿子节点还大于左儿子节点
- if (rightChild < currentSize && heapArray[rightChild] > heapArray[leftChild])
- largeChild = rightChild;
- else
- largeChild = leftChild;
- if (top >= heapArray[largeChild])
- break;
- //不然的话, 则需继续向下渗透
- heapArray[index] = heapArray[largeChild];
- // index需要向下搜索
- index = largeChild;
- }
- //插入
- heapArray[index] = top;
- }
堆排序
堆排序就是将元素一个一个插入到堆中, 然后再一个一个的取出来;
- //堆排序
- template <typename Type>
- void heapSort(Type *begin, Type *end)
- {
- int size = end-begin;
- MaxHeap<Type> maxHeap(size);
- //存入堆中
- for (Type *current = begin; current < end; ++ current)
- maxHeap.push(*current);
- //从堆中取出
- while (begin != end)
- {
- *begin = maxHeap.top();
- ++ begin;
- maxHeap.pop();
- }
- }
- template <typename Type>
- void heapSort(Type *array, int arraySize)
- {
- return heapSort(array, array+arraySize);
- }
附-测试代码:
- int main()
- {
- int array[20];
- for (int i = 0; i < 20; ++i)
- {
- array[i] = rand()%100;
- cout << array[i] << ' ';
- }
- heapSort(array, 20);
- cout << endl;
- for (int i = 0; i < 20; ++i)
- {
- cout << array[i] << ' ';
- }
- cout << endl;
- return 0;
- }
原文地址:http://blog.csdn.net/zjf280441589/article/details/42682141