zoukankan      html  css  js  c++  java
  • 新手讲排序:堆排序 和 认识二叉堆

    二叉堆是完全二叉树或者是近似完全二叉树

     二叉堆满足的二个特性:

    1.父节点的键值总是大于或等于(小于或等于)任何一个子节点的键值

    2.每个节点的左子树和右子树都是一个二叉堆(都是最大堆或者是最小堆)

    当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆,总是小于或等于任何一个子节点的键值时为最小堆

    最小堆最大堆

    堆的存储:

         堆的存储一般是用数组来存储,根据完全二叉树的存储结构,一个节点的父节点为(i-1)/2,一个节点的左孩子为2*i+1,右孩子为2*i+2

                                        实例

    堆的建立插入和删除:

    堆的建立插入删除

    堆得插入:

       每次插入都是将新数据放在数组的最后,可以发现从这个新数据的父节点到根节点必然为一个有序的数列。

    void minHeapAddNumber(int *a,int n,int nNum){
    //在n位置上插入nNum这个数字 a[n]
    =nNum;
    //每一次找到a[n]的父节点,如果a[n]的父节点a[(n-1)/2]小于a[n],则将他们交换,继续往上找
    for(int j=(n-1)/2;(j>=0&&n!=0)&&a[j]<a[n];n=j,j=(n-1)/2){ swap(a[j],a[n]); } }

    堆的删除:

    //节点从i开始,节点总数n 
    //删除的时候每次删除最上面那一个节点(根节点)
    //然后将最后一个元素放在根节点上
    //然后根节点一次与他的左右节点进行比较,找出一个最小的,进行交换,
    //知道到最后一个节点或者中间 没有元素可以交换 
    void minHeapFixDown(int a[],int i,int n){
    	int j,temp;
    	temp=a[i];
    	j=2*i+1;
    	while(j<n){
    		if(j+1<n&&a[j+1]<a[j]){
    			j++;  //右孩子比较小 
    		}
    		if(a[j]>=temp) break;
    		//这里很奇妙,将较小的孩子节点往上移动,
    		//因为上面是和temp进行的比较,所以a[i]=temp这一步可以省略
    		//只在最后出现一次 
    		a[i]=a[j];
    		i=j;
    		j=2*i+1;
    	}
    	a[i]=temp;
    }
    void MinHeapDeleteNumber(int *a,int n){
    	swap(a[0],a[n-1]); //这里已经交换过了
    	MinHeapFixDown(a,0,n-1);  //所以元素个数只剩下了n-1个 
    }
    

     

    堆化数组:

        有了堆的插入和删除函数,在考虑将一个数据进行堆化操作。

    例子:

    可以看出堆化数据的时候,从最后一个非叶子节点开始,那也就是2*i+1=n-1(索引),或者2*i+2=n-1,所以可以得到 i=n/2-1;即为最后一个非叶子结点

    可以得到代码:

    //建立最小堆
    void MakeMinHeap(int *a,int n){
        for(int i=n/2-1;i>=0;i--){
            MinHeapFixDown(a,i,n);
            //也就是把第i个节点从上面慢慢移到正确的位置
            //必须是从上到下排的,这样下面基本是有序的 
        }
    } 

    以上就是堆的基本操作。下面来讲堆排序

    堆排序:

    首先可以得到堆建好之后,第0个元素肯定是最小的,取出这个数据在执行下堆的删除,这样第0个元素又是最小的,重复上述步骤,知道堆中只剩一个元素直接取出。

    由于堆是用数组模拟的,故堆化后,第一次将A[0] 与 A[n-1]交换,再对A[0,n-2]进行恢复,重复直到A[0]与A[1]交换,由于每次都是将最小的数据并入到后面的区间,所以操作完成后整个数组就有序了。所以使用最小堆排序后是递减数组,要得到递增数据,可以使用最大堆

    //堆排序
    void MinHeapSortToDescendArray(int *a,int n){
        for(int i=n-1;i>=1;i--){
            swap(a[0],a[i]);
            MinHeapFixDown(a,0,i);
        }
    } 

    堆排序的时间复杂度:

    由于每次重新恢复堆的时间复杂度是O(logN),共N-1次重新恢复堆操作,再加上前面建立堆时N/2次向下调整,每一次时间复杂度也是O(logN);

    所以堆排序的时间复杂度是O(NlogN);

  • 相关阅读:
    Admin注册和路由分发详解
    自定义Xadmin
    苑昊老师的博客
    pip 国内源 配置
    Django模型层(2)
    Django 中间件
    Django form表单
    整理的最全 python常见面试题(基本必考)
    AJAX
    Cookie、Session和自定义分页
  • 原文地址:https://www.cnblogs.com/jijiji/p/4790719.html
Copyright © 2011-2022 走看看