线性时间排序算法

继续上一次的排序算法的总结,今天带来的是线性时间排序算法

可以看到,我们之前的交换算法时间复杂度最少也只是O(nlogn),那么有没有O(n)的时间复杂度的算法呢,也是有的,就是线性时间排序算法。常见的线性时间算法有:计数排序,基数排序和桶排序,而基数排序和桶排序十分类似,这里只介绍更为普遍的基数排序。

①计数排序

(1)算法思想:计数排序的算法思想比较简单,即我们把序列中一个数之前有多少个数字统计出来,然后直接把这个数放到相应的位置的算法。这种算法的空间要求比较高,因为需要一个数组来储存从0到序列中最大的数的之前的数的个数,所以空间消耗很大。

(2)时间复杂度:O(n^2)

(3)算法描述(吸取教训,从这篇博文开始代码加备注~):

void countinsort(int a[], int b[], int n, int max){
    int i, pos, c[max + 1];   //pos为位置,定义一个长度为序列中最大数加一的数组
    memset(c, 0, sizeof(c));  //将数组初始化置为0
    for(i = 0; i < n; i ++)
        c[a[i]] ++;           //将一个数出现的次数在其相应的位置表示
    for(i = 1; i <= n; i ++)
        c[i] += c[i - 1];     //算出一个数之前的数的个数
    for(i = n - 1; i >= 0; i --){
        int temp = a[i];      
        pos = c[temp];        //得到当前数的前面的数的个数,也就是位置
        b[pos - 1] = temp;    //因为存入数组,所以需要加1
        c[temp] --;           //储存完毕后需要减去已储存的那个数
    }
}

②基数排序

(1)算法思想:基数排序的算法思想是对于序列中的每个数从低位开始互相比较,然后产生新的序列,然后对新的序列的高位互相比较,继续产生新的数列,最后对每一位比较完毕后产生最终的数列。具体实例如图所示

(2)时间复杂度:O(n^2)

(3)算法描述:

int getpos(int n, int pos){
        //取出对应位置的数字
        int temp = 1;
	for(int i = 0; i < pos ;i ++)
		temp *= 10;
	return (n/temp) % 10;     
}

int radixsort(int a[], int n){
	int *b[10];
	int i, j;
	for(i = 0; i < 10; i++){
		b[i] = (int *)malloc(sizeof(int) * (n + 1));//申请一个二维数组,它的横坐标为0-9,纵坐标为序列元素个数
		b[i][0] = 0;		                    //对每行第一个计数元素初始化0
	}
	for(int pos = 1; pos <= 10; pos ++){
		for(i =0; i < n; i ++){
			int number = getpos(a[i], pos);     //取出对应位置的数字
			int index = ++b[number][0];         //对相对应位置数字所在的行的计数元素加1
			b[number][index] = a[i];            //对二维数组对应位置数字所在的行顺序加入原序列中的数字
		}
		for(i = 0, j =0; i < 10; i++){
			for(int k = 1; k <=b[i][0]; k ++){  //将排好一轮序的数组重新生成。
				a[j ++] = b[i][k];
			}
			b[i][0] = 0;                        //重新初始化计数元素
		}
	}
	return 0;
}


③桶排序

桶排序和基数排序类似,是将数字分成n个桶,然后将每个数字除以n然后得到的数放在相应的桶里,对每个非空的桶进行快排,之后顺序存入新的数组。产生最后排好序的数列。


排序算法就说这么多,其实还有一种堆排序也十分常用,但是苦于数据结构的树形结构还未学习,所以暂时不予介绍,待再啃啃数据结构回头再来总结。

posted @ 2015-05-11 12:08  ChiLuManXi  阅读(154)  评论(0编辑  收藏  举报