排序算法总结(三)——堆排序、桶排序

堆排序

排序思想:主要有3个步骤,建立小顶堆(或大顶堆)、删除堆顶数据(删除的数据就是排序的数据)、重新调整为小顶堆。具体可参照MoreWindows的博客《白话经典算法系列之七 堆与堆排序》,文中对堆排序的过程讲解的十分详细,下面堆排序的代码也摘自该Blog。

是否稳定:不稳定。

时间复杂度:堆排序的最坏时间复杂度为O(nlogn)。堆序的平均性能较接近于最坏性能。

//调整堆
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;

		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);
}

//建立最小堆
void MakeMinHeap(int a[], int n)
{
	for (int i = n / 2 - 1; i >= 0; i--)
		MinHeapFixdown(a, i, n);
}

void MinheapsortTodescendarray(int a[], int n)
{
	for (int i = n - 1; i >= 1; i--)
	{
		swap(&a[i], &a[0]);
		MinHeapFixdown(a, 0, i);
	}
}

void my_heap_sort(int a[], int n)
{
	MakeMinHeap(a, n);
    MinheapsortTodescendarray(a, n);
}


桶排序:

排序思想:工作的原理是将阵列分到有限数量的桶子里。每个桶子分别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序)。

排序主要有3个步骤,一是计算需要桶的个数,比如1到100的数字,假设事先设定桶容量大小为10,则桶的个数为10;二是循环待排数列,将元素放入对应的桶中,比如数字35应被放入第4个桶中,同理,数字76应该放入第8个桶中;三是对桶中的数据进行桶内排序,桶内排序方法不做限定,可自己选择。最后按桶的顺序输出桶内数据,即为最后的排序结果。

是否稳定:稳定

时间复杂度:桶排序平均时间复杂度为线性的O(N+C),其中C=N*(logN-logM),N为排序元素的个数,M为桶的个数。

 

以下代码参照了《排序算法——桶排序》一文,添加一些个人注释,帮助大家进一步理解。代码测试的时候,发现当单个桶内的数据个数超出10时,排序会出错。分析代码可知,出错原因是定义barrel结构体时,node的大小固定为10,意味单个桶最大最能容纳10个数据。对于排序数列中没有重复的数据时,可以正确排序,因为此时单个桶中数据个数不会超过10;反之有可能超过10,此时则会排序错误。

struct barrel 
{  
	int node[10];   
    int count;/* the num of node */  
};   
  
void bucket_sort(int data[], int size)   
{   
    int max, min, num, pos;   
    int i, j, k;   
    struct barrel *pBarrel;   
  
	//计算需要桶的个数,其中桶容量为10
    max = min = data[0];   
    for (i = 1; i < size; i++) 
	{   
        if (data[i] > max) 
		{   
            max = data[i];   
        } else if (data[i] < min) 
		{   
            min = data[i];   
        }   
    }   
    num = (max - min + 1) / 10 + 1;   


    pBarrel = (struct barrel*)malloc(sizeof(struct barrel) * num);   
    memset(pBarrel, 0, sizeof(struct barrel) * num);   
  
    //将元素放到对应的桶中
    for (i = 0; i < size; i++) 
	{   
        k = (data[i] - min + 1) / 10;/* calculate the index of data[i] in barrel */ 
        (pBarrel + k)->node[(pBarrel + k)->count] = data[i];   
        (pBarrel + k)->count++;
    }   
    
	//桶内排序
    pos = 0;   
    for (i = 0; i < num; i++) 
	{   
        my_quick_sort((pBarrel+i)->node, 0, (pBarrel+i)->count - 1); //参照上一篇博客《排序算法总结(二)》
  
        for (j = 0; j < (pBarrel+i)->count; j++) 
		{   
            data[pos++] = (pBarrel+i)->node[j];   
        } 
    }   
    free(pBarrel);   
}

 

 

你可能感兴趣的:(排序算法总结(三)——堆排序、桶排序)