博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据结构基础(19) --堆与堆排序
阅读量:4994 次
发布时间:2019-06-12

本文共 4848 字,大约阅读时间需要 16 分钟。

完全二叉树

 

首先让我们回顾一下完全二叉树的两个性质:

  性质1:具有n个结点的完全二叉树的深度为[logn](向下取整)+1。

  性质2:若对含 个结点的完全二叉树从上到下且从左至右进行 至 的编号,则对完全二叉树中任意一个编号为 的结点:

    (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 
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 
MaxHeap
::MaxHeap(int _maxSize) : maxSize(_maxSize),currentSize(0){ if (maxSize < 1) throw std::length_error("heap size must >= 1"); heapArray = new Type[maxSize];}//析构template
MaxHeap
::~MaxHeap(){ delete []heapArray; heapArray = NULL; currentSize = 0;}//判空template
bool MaxHeap
::isEmpty() const{ return currentSize == 0;}

堆顶元素

//查看堆顶元素template 
const Type &MaxHeap
::top() const{ if (isEmpty()) throw std::underflow_error("heap is empty"); return heapArray[0];}

插入元素

//插入template 
void MaxHeap
::push(const Type &item){ //如果堆已满, 则需要对堆进行扩充 if (currentSize == maxSize) { resize(); } //将元素插入到堆的第一个空位置上 heapArray[currentSize] = item; //维护堆的性质:向上渗透 trickUp(currentSize); ++ currentSize;}
//向上渗透, 将刚刚插入的元素移动到合适的位置上template 
void MaxHeap
::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 
void MaxHeap
::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 
void MaxHeap
::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 
void MaxHeap
::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 
void heapSort(Type *begin, Type *end){ int size = end-begin; MaxHeap
maxHeap(size); //存入堆中 for (Type *current = begin; current < end; ++ current) maxHeap.push(*current); //从堆中取出 while (begin != end) { *begin = maxHeap.top(); ++ begin; maxHeap.pop(); }}template
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;}

转载于:https://www.cnblogs.com/itrena/p/5926987.html

你可能感兴趣的文章
mybatis pagehelper实现分页
查看>>
很牛的javascript日期转换函数
查看>>
javascript格式化json显示
查看>>
Redis 在 SNS 类应用中的最佳实践有哪些?
查看>>
关于Unity 动画绘制原理
查看>>
django-xadmin后台开发
查看>>
Canvas链式操作
查看>>
学渣乱搞系列之网络流学习
查看>>
Acdream A - Unique Attack
查看>>
java遍历List的多种方法
查看>>
【投票】你心目中的Excel催化剂价值有多大(附主流国内外收费插件供参考)?...
查看>>
算法复习——半平面交(bzoj2618凸多边形)
查看>>
关于在Intellij Idea中使用JSTL标签库报错的问题
查看>>
如何用自己电脑做服务器,绑定域名建一个个人网站
查看>>
.ds_store是什么文件
查看>>
递归C++
查看>>
POJ 1751 Highways(最小生成树&Prim)题解
查看>>
linux 安装openssh-server, openssh-client
查看>>
Java继承的基本概念及其限制 总结
查看>>
RF1001: 各浏览器对 '@font-face' 规则支持的字体格式不同,IE 支持 EOT 字体,Firefox Safari Opera 支持 TrueType 等字体...
查看>>