zoukankan      html  css  js  c++  java
  • 堆排序

    引子:

    堆排序是第3个比较有意思的排序(相对于 归并排序,快速排序),效率很高,且不用额外的空间。

    堆的定义是:它用一个数组来存储一个完全二叉树(叶子节点只出现在最下层的树)。

    例如如下的数组的10个数据:

    int a[] = {3,4,9,7,5,6,10,8,2,1};


    其实是被看作为:


    不难观察,规律是从 a[0] 到 a[9] 按在树中层次依次排列。

    3的子节点是4和9,即a[0]的子节点是a[1]和a[2]。

    4的子节点是7和5,即a[1]的子节点是a[3]和a[4]。

    9的子节点是6和10,即a[2]的子节点是a[5]和a[6]。

    7的子节点是8和2,即a[3]的子节点是a[7]和a[8]。
    5的子节点是1,即a[4]的子节点是a[9]。

    以此类推,可以得出

    a[n]的子节点是a[2n+1]和a[2n+2] (如果有子节点的话)。


    排序思路:

    堆分两种:

    • 最大堆,即堆顶是数组中的最大数。
    • 最小堆,即堆顶是数组中的最小数。
    大顶堆有一个重要的性质就是父子点永远大于或等于两个子节点。小顶堆则相反。

    假设排序的目标是从小排到大。
    堆排序的第一步是建立最大堆,代码如下:

    	for (int i = nEnd/2 -1; i >= 0 ; i--)
    	{
    		HeapAdjust( ua, i, nEnd);
    	}

    主要目的就是让堆中的最大值跑到堆顶去。

    void HeapAdjust(int* ua, int nStart, int nEnd)
    {
    	int nMaxIndex = 0;
    
    	while ( ( 2*nStart + 1) < nEnd )  
    	{  
    		nMaxIndex = 2*nStart + 1;  
    		if ( ( 2*nStart + 2) < nEnd)  
    		{  
    			//比较左子树和右子树,记录较大值的Index  
    			if (ua[2*nStart + 1] < ua[2*nStart + 2])  
    			{  
    				nMaxIndex++;  
    			}  
    		}  
    
    		//如果父结点大于子节点,则退出,否则交换
    		if (ua[nStart] > ua[nMaxIndex])  
    		{  
    			break;
    		}  
    		else
    		{
    			swap( ua[nStart], ua[nMaxIndex] );
    			//堆被破坏,继续递归调整(注意,这里是递归的关键)
    			nStart = nMaxIndex;  
    		}
    	}  
    }

    这样数组经过调整后就变成了:
    之前:
    {3,4,9,7,5,6,10,8,2,1};

    之后:
    {10,8,9,7,5,6,3,4,2,1};

    这样最大值10就跑到堆顶了。


    堆排序的第二步是:每次把堆顶的数与堆的最后一个数交换,再让最后一个数脱离堆,然后继续建最大堆。然后如此循环,直到只剩下堆顶的数。

    比如第一轮把堆顶的10与1交换,此时1在堆顶,让10从堆中脱离,让10放在数组的末尾。此时堆还有9个数,最后1个数10留在末尾。


    第二轮先建堆,让9在堆顶,然后让9和2交换,此时2在堆顶,让9从堆中脱离,主9放在数组的倒数第2个位置,此时堆还有8个数,最后两个数是9,10。


    如此不堆的递归,直到堆越来越小,数组越来越大,并且是排序的状态。最后堆就没有了。

    代码如下:

    	for (int i = nEnd-1; i > 0; i--)
    	{
    		swap(ua[0], ua[i]);
    		HeapAdjust(ua, 0, i);
    	}

    完整的代码如下:
    #include "stdafx.h"
    #include "windows.h"
    #include "time.h"
    
    
    const int N = 10;
    int O = 0;
    
    int* GenRandom()
    {
    srand( (unsigned)time( NULL ) );
    
    
    int* a = new int[N];
    for (int i = 0; i < N; i++)
    {
        a[i] = rand() ;
    }
        return a;
    }
    
    
    void swap(int& a, int& b)
    {
        int temp = 0;
        temp = a;
        a = b;
        b = temp;
    }
    
    void HeapAdjust(int* ua, int nStart, int nEnd)
    {
    	int nMaxIndex = 0;
    
    	while ( ( 2*nStart + 1) < nEnd )  
    	{  
    		nMaxIndex = 2*nStart + 1;  
    		if ( ( 2*nStart + 2) < nEnd)  
    		{  
    			//比较左子树和右子树,记录较大值的Index  
    			if (ua[2*nStart + 1] < ua[2*nStart + 2])  
    			{  
    				nMaxIndex++;  
    			}  
    		}  
    
    		//如果父结点大于子节点,则退出,否则交换
    		if (ua[nStart] > ua[nMaxIndex])  
    		{  
    			break;
    		}  
    		else
    		{
    			swap( ua[nStart], ua[nMaxIndex] );
    			//堆被破坏,继续递归调整  
    			nStart = nMaxIndex;  
    		}
    	}  
    	for (int i = 0; i < N; i++)
    	{
    		printf("%d ",ua[i]);
    	}
    	printf("
    ");
    	//printf("%d ", O++);
    }
    
    void HeapSort(int* ua, int nStart, int nEnd)
    {
    	for (int i = nEnd/2 -1; i >= 0 ; i--)
    	{
    		HeapAdjust( ua, i, nEnd);
    	}
    
    	for (int i = nEnd-1; i > 0; i--)
    	{
    		swap(ua[0], ua[i]);
    		HeapAdjust(ua, 0, i);
    	}
    }

    SYSTEMTIME StartTime = {0};
    FILETIME StartFileTime = {0};
    SYSTEMTIME EndTime= {0};
    FILETIME SEndFileTime= {0};
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	//int* a = GenRandom();
    	int a[] = {3,4,9,7,5,6,10,8,2,1};
    	GetLocalTime(&StartTime);
    	printf("timeBefore %d:%d:%d 
    ", StartTime.wMinute, StartTime.wSecond, StartTime.wMilliseconds);
    
    	HeapSort(a, 0, N);
    
    	GetLocalTime(&EndTime);
    	printf("timeAfter %d:%d:%d 
    ", EndTime.wMinute, EndTime.wSecond, EndTime.wMilliseconds);
    	printf("times %d 
    ", O);
    	return 0;
    }
    



             

  • 相关阅读:
    LeetCode 109 Convert Sorted List to Binary Search Tree
    LeetCode 108 Convert Sorted Array to Binary Search Tree
    LeetCode 107. Binary Tree Level Order Traversal II
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode 103 Binary Tree Zigzag Level Order Traversal
    LeetCode 102. Binary Tree Level Order Traversal
    LeetCode 104. Maximum Depth of Binary Tree
    接口和多态性
    C# 编码规范
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3217678.html
Copyright © 2011-2022 走看看