zoukankan      html  css  js  c++  java
  • 重学数据结构系列之——堆及堆排序

    学习来源:计蒜客

    1.定义

    满足一下两个条件
    1.首先它是一颗完全二叉树(就是除了最后一层,每个结点都有两个孩子,最后一层只缺少右边的若干结点。)看看这个就明白:http://baike.baidu.com/pic/完全二叉树/7773232/0/906289ddefbfa4745882dd18?fr=lemma&ct=single#aid=0&pic=906289ddefbfa4745882dd18

    2.越是顶端,结点的权值越大,并且它的权值大于等于它所在子树的所有结点的权值。(注意这里是所有结点,但不是所有结点之和啦)

    2.分类


    根结点权值大于等于树中结点权值的堆称为大根堆
    根结点权值小于等于树中结点权值的堆称为小根堆

    3.储存

    用数组储存就好,当然我们计算机里面是从0开始编起的



    4.实现

    #include <iostream>
    
    using namespace std;
    
    class Heap{
    private:
    	int *data, size;
    public:
    	//length_input:堆的最大容量
    	Heap(int length_input){
    		data = new int[length_input];
    		size = 0;
    	}
    	~Heap(){
    		delete[] data;
    	}
    	//插入
    	void push(int value){
    		//先放在堆中最后一个元素的后一个位置,注意这里的size是堆暂时的大小,跟堆的最大容量是不一样的
    		data[size] = value;
    		//用current储存插入元素的索引
    		int current = size;
    		//父亲结点的数组索引
    		int	father = (current-1)/2;
    		//如果插入的值大于父亲,就交换,注意索引值也要更新
    		while (data[current] > data[father]) {
    			//值交换
    			swap(data[current], data[father]);
    			//插入元素的索引,更新为父亲的索引
    			current = father;
    			//同时也计算出新的父亲的索引
    			father = (current-1)/2;
    		}
    		//插入后,堆的大小+1
    		size++;
    	}
    	//遍历输出
    	void output(){
    		//就像数组一样就行了
    		for (int i = 0; i < size; i++) {
    			cout<<data[i]<<" ";
    		}
    		cout<<endl;
    	}
    	//返回堆顶元素
    	int top(){
    		return data[0];
    	}
    	//自上而下调整堆
    	//pos:当前要调整的位置
    	//n:当前堆中的元素个数
    	void update(int pos, int n){
    		//计算出左右孩子的索引值,等下比较pos位置的元素跟其左右孩子元素的大小
    		int lchild = 2 * pos + 1, rchild = 2 * pos + 2;
    		//初始化这三个的最大值的索引为pos
    		int max_value = pos;
    		//首先索引要小于堆的大小,其次要值大于max_value位置的值,那么就更新max_value
    		if (lchild < n && data[lchild] > data[max_value]) {
    			max_value = lchild;
    		}
    		if (rchild < n && data[rchild] > data[max_value]) {
    			max_value = rchild;
    		}
    		//经过上面的两个if,max_value绝对是三个中最大值得索引了,
    		//如果不等于pos,那大的值就往上走,等于pos的话就不用再做任何操作了
    		if (max_value != pos) {
    			//进入到这里max_value肯定是左右孩子的值了,但我们不用管,有索引值就好
    			swap(data[pos], data[max_value]);
    			//两个元素值交换后,再递归调整
    			update(max_value, n);
    		}
    	}
    	//删除堆顶元素
    	void pop(){
    		//先将最后一个元素与堆顶元素的值交换
    		swap(data[0], data[size-1]);
    		//堆的大小减1,就相当于将最后的元素删除了
    		size--;
    		//再自上而下调整位置0,即新的堆顶的位置,size为堆的大小
    		update(0, size);
    	}
    	//堆排序
    	//注:本数据结构的堆为大根堆
    	void heap_sort(){
    		//从最后一个元素开始,将它与根值交换,再自上而下调整堆
    		for (int i = size -1; i >= 1; i--) {
    			//与堆顶元素交换,那么交换后最后一个元素data[size-1]的值是最大的,因为是大根堆
    			swap(data[i], data[0]);
    			//再自上而下调整堆,注意第i+1个及以后已经是升序排列,所以只需调整前i个
    			//其实这里是将前i个中最大的值调整到堆顶,即data[0]
    			update(0, i);
    		}
    	}
    };
    
    int main(){
    	int arr[10] = { 12, 9, 30, 24, 30, 4, 55, 64, 22, 37 };
    	Heap heap(100);
    	for (int i = 0; i < 10; i++) {
    		heap.push(arr[i]);
    	}
    	//输出
    	heap.output();
    	cout<<heap.top()<<endl;
    	heap.pop();
    	heap.output();
    	//堆排序
    	heap.heap_sort();
    	heap.output();
    	return 0;
    }

    5.运行结果





  • 相关阅读:
    MYSQL导入,导出命令。
    MySQL修改,表结构大幅修改
    Ajax
    js和jQuery的日常
    freemarker 分页取值
    Timer定时任务
    汉字相似度比较
    读取Properties键值对
    Python+requests+unittest+excel实现接口自动化测试框架
    Android App 压力测试方法(Monkey)
  • 原文地址:https://www.cnblogs.com/cnsec/p/13286552.html
Copyright © 2011-2022 走看看