zoukankan      html  css  js  c++  java
  • 非比较排序算法———计数排序

    计数排序、基数排序、桶排序 非比较排序算法,平均时间复杂度都是O(N).

    这些排序元素,因为其关键值本身就含有了定位特征,因而不需要比较就可以确定其前后位置。

    1、计数排序是一种简单的排序方法,将排序结果放到另一个的新的数组中。

          计数排序要求 待排序的元素的关键值是位于0-k之间的正整数。因而是个非常特殊的情况。

          输入数组A:元素关键值是 0-K的正整数,可以有重复值

          输出数组B:输出数组A的一个非减序列

          中间数组C:大小K,它的i(0<=i<=k)索引位置存储的是A元素集合和。

          这里意思是:原始数组A元素变成了中间数组C下标。       

          
    void Sort(int array[],int n,int outArray[],int k) //默认 区间是0——K
    {
    	int* Temp=new int[k+1];
    	memset(Temp,0,(k+1)*sizeof(int));     
    	for(int i=0;i<n;i++)
    	    Temp[array[i]]++;
    	int m=0;
    	for (int i=0;i<=k;i++)
    	{
    	  while(Temp[i]-->0)//如果有重复的话要递减
              outArray[m++]=i; //array[m++]也是可以的 这里是标准计数排序的优化 可以使outArray 省去
    	}
    	delete[] Temp;
    }
    

      第一次我以为这就是计数排序,但后来发现 这个算法虽然可以解决有限区间的排序问题。但不是标准的(算法导论上)计数排序。

    这个算法严格的来说并非排序算法,像统计(引用别人的描述)。所以也就不是什么稳定排序与非稳定排序,因为排序后的数组中的数已尽被全新的数替代。 已尽改变以前的数组中元素。

    引用:维基百科计数排序

    当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。

    由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序中的算法来排序数据范围很大的数组。

    算法的步骤如下:

    1. 找出待排序的数组中最大和最小的元素
    2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i
    3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
    4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
    void BookSort(int array[],int outarray[],int n,int k)
    {
        //标准排序
        int* Temp=new int[k+1];
        memset(Temp,0,(k+1)*sizeof(int));     
        for(int i=0;i<n;i++)
            Temp[array[i]]++;
        for (int i=1;i<=k;++i)
        {
            Temp[i]=Temp[i]+Temp[i-1];
        }
        //for (int i=n-1;i>=0;--i) //从后往前遍历原始数组 是稳定排序
        for (int i=0;i<n;++i) //从前往后遍历原始数组 就不再是稳定排序
        {
            //计数排序核心思想
            int m=array[i];//原始数组元素关键字的值
            int q=Temp[m];//根据原始数组元素关键字的值 对应于临时数组的下标 找到临时数组的值
            outarray[ q- 1] = array[i];//临时数组的值 即是原始数组原始关键字的 排序位置
            Temp[m] =Temp[m]-1;//因为有重复的数 排序的位置需要减去一个
        }
    }

     代码测试:

    int N=20;
        int array[]={0,0,8,9,6,9,4,0,6,0,0,5,65,76,77,8,79,98,89,96};
        int* outArray=new int[N];
        Sort(array,N,outArray,100);
        //BookSort(array,outArray,N,100);
        for (int i=0;i<N;++i)
        {
            cout<<outArray[i]<<" ";
        }
        system("PAUSE");
        return EXIT_SUCCESS;

     总结:

           计数排序要求规则太多,内存要求很大。接下来我会将其它线性排序算法写一写。然后直接做比较以及和其他非线性排序之间的比较。

    文中肯定存在错误,请您如果发现任何有疑问的地方给我信息。谢谢...

    PS:C++ 知识点

    初始化中间数组C 运用 C++ 函数 void *memset(void *s,int c,size_tn)    memset是对字节进行操作

    char a[5];  memset(a,'1',5); 可以全部初始化为'1'

    int a[5]; memset(a,0,5); 并不能全部初始化为0 因为是按字节进行初始化的 所以应该 memset(a,0,5*sizeof(int));

     

    指针的大小是问:一个指针变量占用多少内存空间?分析:既然指针只是要存储另一个变量的地址,。注意,是存放一变量的地址,而不是存放一个变量本身,所以,不管指针指向什么类型的变量,它的大小总是固定的:只要能放得下一个地址就行!32位系统存放一个地址需要几个字节?答案是和一个 int 类型的大小相同:4字节。

    指向数组的指针: int arr[] = {1,2,3,4,5}; //一个数组

    int* parr; //一个指针。parr = arr; //没有&?对啊,对数组就是不用取址符。

    cout << *parr << endl;  //输出 *parr    正确答案是输出数组中的第一个元素: 1 。

    重点 & 易错点:对指针 进行加1操作,得到的是下一个元素的地址,而不是原有地址值直接加1。知到了如何“加”,也就知道了如何“减”。减以后,得到的是上一个元素的大小。所以,一个类型为 T 的指针的移动,以 sizeof(T) 为移动单位。int* pInt; 移动单位为 sizeof(int) 。即:4。而 char* pChar; 移动单位为 sizeof(char)。即1。

    后置 ++ 或 后置-- 操作,需要系统生成一个临时变量。

     * (作为地址解析符) ++ 同时作用在指针时,不管是前置还是++,都要比*有更高的优先级。

    指针和数组是不一样的,但数组做为参数传递时就会退化为同类型的指针.

    有2个原则:对数组sizeof是数组的大小;对指针sizeof是指针的大小(4);

    学习技术不只是为养家糊口,也为夜深人静的时候能够一个人静静享受这其中的乐趣。
  • 相关阅读:
    Windows Azure Web Site (19) Azure Web App链接到VSTS
    Windows Azure Virtual Machine (35) Azure VM通过Linked DB,执行SQL Job
    Azure PowerShell (16) 并行开关机Azure ARM VM
    Windows Azure Virtual Network (12) 虚拟网络之间点对点连接VNet Peering
    Azure ARM (21) Azure订阅的两种管理模式
    Windows Azure Platform Introduction (14) 申请海外的Windows Azure账户
    Azure ARM (20) 将非托管磁盘虚拟机(Unmanage Disk),迁移成托管磁盘虚拟机(Manage Disk)
    Azure ARM (19) 将传统的ASM VM迁移到ARM VM (2)
    Azure ARM (18) 将传统的ASM VM迁移到ARM VM (1)
    Azure Automation (6) 执行Azure SQL Job
  • 原文地址:https://www.cnblogs.com/renxs/p/2657377.html
Copyright © 2011-2022 走看看