zoukankan      html  css  js  c++  java
  • 排序元素三种线性时间排序算法 C++实现

    这两天朋友几篇文章介绍了改排序元素的文章. 关联文章的地址

        引言

        

        :由于没有启用任何公式编辑器,为表示便利:以下触及时光复杂度表示时,其渐近符号用以下符号代替:

        排序和元素

        先来看一个定理:任意一个比较排序算法在最坏情况下,都需要做 $(nlgn)次的比较。其可用决策树模型加以证明,详见:《算法导论》第8章8.1节。

        该定理指出了比较排序的时光复杂度下界,即没有比较更少的了。

        故以下介绍的三种算法均不是基于比较的排序算法,其均对输入数据作了某种假设,即利用了具体数据的特色。

        

        一、计数排序

        

        1、问题描述假设数组中的n个元素中的每个都是介于0到k之间的整数,对其停止排序。此处k为某个正整数。

        2、基本思想:对每个输入元素x,利用它的所属范围巨细为[0, k] ,确定出数组中小于x 的元素个数。由于x为正整数,则可以直接把x直接放到它在终究输出数组中的位置上。

        3、算法描述

        输入:A[1...n], 输入数组;C[0...k],提供临时存储区,初值:0   ---O(k)

        输出:B[1...n],存放排序结果

        (1)求出输入数组A[]1...n]中,其值等于A[j]的元素个数,存放于对应的C[1...k]中:C[A[i]] = C[A[i]] + 1   ---O(n)

        (2)求出输入数组A[]1...n]中,其值小于或等于A[j]的元素个数,迭代地存放于对应的C[1...k]中:C[j] = C[j-1] + C[j]   ---O(K)

        (3)经过前两步以后,C[i]中的值表示为:小于等于 i 的元素个数,即 为 i 在A[1...n]中的终究位置,将其存放于B[1...n]中:B[C[A[j]]] = A[j], C[A[j]] = C[A[j]] - 1 (有可能存在想相称的元素)   --- O(n)

        4、时光复杂度:O(k)  + O(n) + O(k) + O(n),则总的运行时光为:@(k+n),在实践中,当 k=O(n)时,其运行时光即为:@(n).

        5、算法实现

    #include <stdio.h>
    const int K = 5;
    const int N = 6;
    int input[N+1] = {-1, 2, 3, 4, 2 ,1, 5};
    int output[N+1];
    int count[K]={0};
    
    void print(int array[], int n)
    {
    	for(int i = 1; i <=n; i++)
    	{
    		printf("%d ", array[i]);
    	}
    	printf("\n");
    }
    void countSort(int input[], int output[], int n)
    {
    	int i;
    	for(i = 1; i <= n; i++)
    	{//equal to input[i]
    		count[input[i]] = count[input[i]] +1;
    	}
    	for(i = 1; i <= K; i++)
    	{//less ro equal to i
    		count[i] = count[i-1] + count[i];
    	}
    	for(i = n; i >= 1; i--) //form large to small to make sorting stable
    	{
    		output[count[input[i]]] = input[i];
    		count[input[i]]--;
    	}
    }
    
    int main()  
    {
    	countSort(input, output, N);
    	print(output, N);
        return 0;  
    }

        二、基数排序

        

        1、问题描述:给定n个d位数,每一位可能的取值有k中,对其停止排序。如,4个三位数:123,367,124,756,此时n=4, d=3,k值为10.

        2、基本思想:首先按最低有效位数字停止排序,搜集结果;然后按次低位有效位数字排序,搜集其结果,依次类推,重复这个进程,直到对所有的d位数字都停止 了排序。

        看个例子(来自算法导论8.3的示例,P100):

        排序和元素

        注意:对每一位的排序必须是一个稳定的排序,否则排序可能不正确。如上图在对最高位排序时,起初436在457的前面,由于最高位都是4,故此次排序两个数的最高位相称,如果不是稳定的排序,结果457可能会排到436的前面,这样结果就不对了。而稳定的排序则可以保障排完后,436仍然在457的前面。

        3、算法描述

        输入数组:A[1...n]

        RADIX-SORT(A, d)

        for i <- 1 to d

             do use a stable sort to sort array A on digit i  //可以选择计数排序

        4、时光复杂度:由一中的计数排序可知,对每一位的排序时光为:@(k+n),此处共执行d遍,故时光复杂度:@(d*(k+n)),当d为常数、k=O(n)时,基数排序有线性运行时光:@(n)。更一般且更具体的分析可以参加《算法导论》的引理8.3和8.4,P101,其详细分析了:如何将每个关键字分解成若干位以及那些情况下时光复杂度最好。此处只介绍一些结论与如何实现之。

        5、算法实现

        每日一道理
    当浮华给予我们过多欺骗,现实中的虚假几乎让我们忘却了真的存在,是真情唤回了迷离的心,是真情带给了我们最纯、最真的感觉,它流露的是美的誓言,渗透的是永恒执著的真爱。
    #include <stdio.h>
    #include <math.h>
    const int N = 7;
    const int D = 3;
    const int K = 10;
    int count[K] = {0};
    //int input[N+1] = {-1, 329, 457, 657, 839, 436, 720, 355};
    int output[D+1][N+1]={{-1, 329, 457, 657, 839, 436, 720, 355}};
    
    void print(int array[], int n)
    {
    	for(int i = 1; i <=n; i++)
    	{
    		printf("%d ", array[i]);
    	}
    	printf("\n");
    }
    int getDigit(int number, int d)
    {
    	if(d > D)return -1;
    	return number%(int)pow(10,d) / (int)pow(10,d-1); 
    }
    void countSort(int input[], int output[], int n, int d)
    {
    	int i;
    	int digit;
    	for(i = 1; i <= n; i++)
    	{
    		digit = getDigit(input[i],d);
    		count[digit] = count[digit] +1;
    	}
    	for(i = 1; i <= K; i++)
    	{
    		count[i] = count[i-1] + count[i];
    	}
    	for(i = n; i >= 1; i--) //form large to small to make sorting stable
    	{
    		digit = getDigit(input[i],d);
    		output[count[digit]] = input[i];
    		count[digit]--;
    	}
    }
    void initDataStruct(int count[])
    {
    	for(int i= 0; i < K; i++)
    	{
    		count[i] = 0;
    	}
    }
    void radixSort(int output[][N+1], int n, int d)
    {
    	for(int i = 1; i <= d; i++)
    	{
    		countSort(output[i-1], output[i], n, i);
    		initDataStruct(count);
    	}
    }
    
    int main()  
    {
    	radixSort(output, N, D);
    	print(output[D], N);
            return 0;  
    }

        三、桶排序

        

        1、问题描述假设输入数组有一个随机进程发生,该进程将元素均匀地分布在区间 [0, 1)上,对这个输入数组停止排序

        2、基本思想:类似于散列表中处理散列冲突的拉链法,一个桶实质就是一个链表,将相同关键字的元素会被放入同一个桶中。由于输入数组中的元素均匀且独立均匀分布在 [0, 1)上,所以一般不会有很多个元素被分到同一个桶中去。散列完成后,先对各个桶中的元素停止排序,然后按顺序把各桶中的元素搜集出来即失掉一个有序的数组。

        3、算法描述

        输入:A[1...n];B[0...n-1]:帮助数组链表,用于散列元素

        输出:排序好的A[1...n]

        (1)把区间 [0, 1) 划分成 n个相同巨细的子区间,或称为桶(可用帮助数组链表B[0...n-1) 实现之)。

        (2)已知,散列函数为:f(x) = floor(n*x) , 向下取整,则数组元素A[i] 分配至 桶(链表)B[floor(n*A[i])]中    ---@(n)

        (3)分别对每个桶B[i]中的元素停止排序(可用插入排序实现之)    ---n*O(2-1/n)

        (4)按顺序搜集各桶中的结果。

        4、时光复杂度:根据3中的算法描述部份可知,除了第(3)步外,其他各部份在最坏情况下的时光都是O(n)。应用数理统计的知识可以求得,第(3)步中的对每个桶停止排序,运行时光的期望值为:2-1/n(详见:《算法导论》8.4节,P103),则第(3)步的总时光:n*(2-1/n),故桶排序的期望运行时光:@(n) + n*(2-1/n) =@(n)

        5、算法实现

    #include <stdio.h>
    #include <math.h>
    
    const int N =10;
    double input[N+1] = {-1, 0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21, 0.12, 0.23, 0.68};
    typedef struct BucketNode
    {
    	double data;
    	struct BucketNode* next;
    }* bucketList, bucketNode;
    bucketList bucketArr[N];
    
    void print(bucketList bucketArr[])
    {	
    	for(int i = 0; i < N; i++)
    	{
    		bucketNode* pb = bucketArr[i];
    		while(pb)
    		{
    			printf("%e ", pb->data);
    			pb = pb->next;
    		}
    		printf("\n");
    		
    	}
    	printf("\n");
    }
    
    void initBucketList(bucketList bucketArr[])
    {
    	for(int i = 0; i < N; i++)
    	{
    		bucketArr[i] = NULL;
    	}	
    }
    bool insertBucketWithSorting(bucketList& bucket, double data)
    {//sorting while inserting
    	bucketNode* pb = new bucketNode;
    	if(NULL == pb)
    		return false;
    	pb->data = data;
    	if(NULL == bucket || pb->data < bucket->data)
    	{//insert before the first element
    		pb->next = bucket;
    		bucket = pb;		
    		return true;
    	}
    
    	bucketNode* ptemp = bucket;
    	bucketNode* ptempn = bucket->next;
    	while(ptempn)
    	{//insert after the first element(that is in the middle)
    		if(pb->data < ptempn->data)
    		{
    			pb->next = ptempn;
    			ptemp->next = pb;
    			break;
    		}
    		ptemp = ptempn;
    		ptempn = ptempn->next;
    	}
    	if(NULL == ptempn)
    	{//insert after the last element
    		ptemp->next = pb;
    		pb->next = NULL;
    	}
    
    	return true;
    }
    
    void destroyBucketList(bucketList bucketArr[])
    {
    	for(int i = 0; i < N; i++)
    	{
    		while(bucketArr[i]!= NULL)
    		{
    			bucketNode* pb = bucketArr[i];
    			bucketArr[i] = bucketArr[i]->next ;
    			delete pb;
    			pb = NULL;
    		}
    	}
    	
    }
    void bucketSort(double input[], bucketList bucketArr[],int n)
    {	
    	for(int i = 1; i <= n; i++)
    	{
    		int index = (int)floor(input[i]*n);
    		insertBucketWithSorting(bucketArr[index], input[i]);
    	}	
    
      }
    
    int main()  
    {
    	initBucketList(bucketArr);
    	bucketSort(input, bucketArr, N);
    	print(bucketArr);
    
    	destroyBucketList(bucketArr);
    
        return 0;  
    }

        

    文章结束给大家分享下程序员的一些笑话语录: 与女友分手两月有余,精神萎靡,面带菜色。家人介绍一女孩,昨日与其相亲。女孩果然漂亮,一向吝啬的我决定破例请她吃晚饭。
    选了一个蛮贵的西餐厅,点了比较贵的菜。女孩眉开眼笑,与我谈得很投机。聊着聊着,她说:“我给你讲个笑话吧。”“ok”
      “一只螳螂要给一只雌蝴蝶介绍对象,见面时发现对方是只雄蜘蛛。见面后螳螂问蝴蝶‘如何?’,‘他长的太难看了’,‘别看人家长的丑,人家还有网站呢’。”
      “呵呵………”我笑。忽然她问:“你有网站吗?”  

  • 相关阅读:
    Java并发之AQS详解
    Linux查看日志常用命令
    换了电脑如何使用hexo继续写博客
    职业保持年轻感
    如何用区块链技术解决信任问题?Fabric 架构深度解读
    一致性哈希(hash)算法
    你真的了解volatile关键字吗?
    Spring的IOC原理
    使用Hexo+Github搭建属于自己的博客(进阶)
    使用Hexo+Github搭建属于自己的博客(基础)
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3076701.html
Copyright © 2011-2022 走看看