数据结构与算法学习--排序(桶排序,计数排序,基数排序)

基数排序和计数排序可以参照链接

桶排序:
桶排序 (Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将阵列分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的阵列内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。
例如要对大小为[1…1000]范围内的n个整数A[1…n]排序,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1…10]的整数,集合B[2]存储(10…20]的整数,……集合B[i]存储((i-1)10, i10]的整数,i = 1,2,…100。总共有100个桶。然后对A[1…n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。 然后再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任何排序法都可以。最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这样就得到所有数字排好序的一个序列了。
假设有n个数字,有m个桶,如果数字是平均分布的,则每个桶里面平均有n/m个数字。如果对每个桶中的数字采用快速排序,那么整个算法的复杂度是O(n+mn/mlog(n/m))=O(n+nlogn-nlogm)
从上式看出,当m接近n的时候,桶排序复杂度接近O(n)
当然,以上复杂度的计算是基于输入的n个数字是平均分布这个假设的。这个假设是很强的,实际应用中效果并没有这么好。如果所有的数字都落在同一个桶中,那就退化成一般的排序了。

下面是三种排序算法的C代码实现。

/*************************************************************************
 > File Name: sort.c
 > Author:  jinshaohui
 > Mail:    [email protected]
 > Time:    18-10-20
 > Desc:    
 ************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<assert.h>

void dump(int a[],int size)
{
	int i = 0;

	printf("\r\n");

	for(i = 0; i <size; i++)
	{
		printf("%d ",a[i]);
	}
	printf("\r\n");
}

/*计数排序,时间复杂度0(n),非原地排序
 *计数排序也是利用桶排序的解决方式
 * 如果数组最大值max比数组大小size大很多不适合;
 * 计数排序要求时非负整数
 * */
void count_sort(int a[],int size)
{
	int i = 0;
	int max = 0;
	int *count = 0;
	int *res = 0;

	/*找到最大数*/
	for (i = 0 ; i< size; i++)
	{
		if (a[i] > max)
		{
			max = a[i];
		}
	}

	count = (int *)malloc(sizeof(int)*(max + 1));
	assert(count != NULL);

	memset(count,0,sizeof(int)*(max + 1));

	/*计数*/
	for (i = 0; i < size;i++)
	{
		count[a[i]]++;
	}
	
	/*依次累加*/
	for(i = 1 ;i <= max; i ++)
	{
		count[i] += count[i-1];
	}

	res = (int *)malloc(sizeof(int)*(size));
	assert(res != NULL);
    /*核心代码,count[a[i] - 1]就是排序好的下标*/
	for (i = size-1;i >= 0; i--)
	{
		res[count[a[i]] -1] = a[i];
		count[a[i]]--;
	}
    
	memcpy(a,res,size*(sizeof(int)));

	free(res);
	free(count);
	return;
}


int count_sort_test()
{
	int a [10]={1,5,6,8,10,9,3,1,2,1};
    printf("\r\n conunt sort test ....");
	count_sort(a,10);
	dump(a,10);

	return 0;
}

#define NUM_OF_POS(a,pval) ((a)/pval)%10
void radix_sort(int a[],int size,int num_count)
{
	int count[10] = {0}; /*计数*/
	int *pres = NULL;
	int i = 0;
	int j = 0;
	int pval = 10;
	int index = 0;
	int break_flg = 0;

	pres = (int *)malloc(sizeof(int)*size);
	assert(pres != NULL);

	for (i = 0; i < num_count; i ++)
	{
		memset(count,0,sizeof(int)*10);

		/*求当前的基数*/
        pval = pow(10,i);

	    /*计数*/
		for (j = 0; j < size; j++)
		{
			index = NUM_OF_POS(a[j],pval);
			count[index]++;
		}

		/*小的优化,可能位数最大的就1,其他的位数差很多*/
		if(count[0] == 9)
		{
			break_flg++;
		}

		if(break_flg >=2)
		{
			printf("\r\n %i",i);
			break;
		}

		/*累加*/
		for(j = 1; j < 10; j ++)
		{
			count[j] += count[j-1];
		}

		/*排序必须从后往前,否则不是稳定排序*/
		for(j = size -1; j >= 0; j--)
		{
			index = NUM_OF_POS(a[j],pval);
            pres[count[index] - 1] = a[j];
			count[index]--;
		}
        /*本轮排序好的,拷贝到a中*/
		memcpy(a,pres,sizeof(int)*size);
	}

	return;
}

void radix_sort_test()
{
	int a[10] = {123,12341,1232134,124,236,128,1112313129,98,9,8989};
    printf("\r\n radix sort test.....");
	radix_sort(a,10,10);
	dump(a,10);
	return;
}

struct barrel {   
    int node[10];   
    int count;/* the num of node */  
};   
int partition(int a[],int left,int right)
{
   int i = left;
   int j = right;
   int key = a[left];

   while(i < j)
   {
	   while((i < j)&& (a[j] >= key))
	   {
		   j--;
	   }
	   if (i < j)
	   {
		   a[i] = a[j];
	   }
	   while((i < j) && a[i] <= key)
	   {
		   i++;
	   }

	   if (i<j)
	   {
		   a[j] = a[i];
	   }
   }
   a[i] = key;

   return i;
}

void quick_sort(int a[],int left,int right)
{
	int q = 0;
	/*递归终止条件*/
	if (left >= right)
	{
		return;
	}

	q = partition(a,left,right);
	quick_sort(a,left,(q - 1));
	quick_sort(a,(q + 1),right);
	return;
}
  
void bucket_sort(int data[], int size)   
{   
    int max, min, num, pos;   
    int i, j, k;   
    struct barrel *pBarrel;   
  
    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);   
  
    /* put data[i] into barrel which it belong to */  
    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++) {
		if ((pBarrel + i)->count != 0)
		{
            quick_sort((pBarrel+i)->node, 0, ((pBarrel+i)->count)-1);/* sort node in every barrel */  
  
            for (j = 0; j < (pBarrel+i)->count; j++) {   
                data[pos++] = (pBarrel+i)->node[j];   
            }
		}
    }   
    free(pBarrel);   
}

void bucket_sort_test()
{
	int a[] = {78, 17, 39, 26, 72, 94, 21, 12, 23, 91};   
    int size = sizeof(a) / sizeof(int);   
	printf("\r\n bucket sort test ...");
    bucket_sort(a, size); 
	dump(a,size);
	
}

int main()
{
    count_sort_test();

	radix_sort_test();

	bucket_sort_test();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jsh13417/article/details/83550148