排序算法分类

本文深入讲解十大经典排序算法,包括冒泡、选择、插入、归并、快速、堆、希尔、计数、基数排序,以及桶排序。文章通过图表、动图和核心代码详细解析每种算法的工作原理、时间与空间复杂度、稳定性特点,帮助读者全面掌握排序算法的精髓。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写的非常好,原问连接:https://blog.youkuaiyun.com/yushiyi6453/article/details/76407640

这里写图片描述

排序算法比较表格填空

排序算法平均时间复杂度最坏时间复杂度空间复杂度是否稳定
冒泡排序:————-::—–::—–::—–:
选择排序:————-::—–::—–::—–:
直接插入排序:————-::—–::—–::—–:
归并排序:————-::—–::—–::—–:
快速排序:————-::—–::—–::—–:
堆排序:————-::—–::—–::—–:
希尔排序:————-::—–::—–::—–:
计数排序:————-::—–::—–::—–:
基数排序:————-::—–::—–::—–:

排序算法比较表格

排序算法平均时间复杂度最坏时间复杂度空间复杂度是否稳定
冒泡排序O(n2)O(n2)O(n2)O(1)O(1)
选择排序O(n2O(n2)O(n2)O(1)O(1)不是
直接插入排序O(n2O(n2)O(n2)O(1)O(1)
归并排序O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(n)O(n)
快速排序O(nlogn)O(nlogn)O(n2)O(n2)O(logn)O(logn)不是
堆排序O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(1)O(1)不是
希尔排序O(nlogn)O(nlogn)O(ns)O(ns)O(1)O(1)不是
计数排序O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)
基数排序O(N∗M)O(N∗M)O(N∗M)O(N∗M)O(M)O(M)


1 归并排序可以通过手摇算法将空间复杂度降到O(1),但是时间复杂度会提高。注:

2 基数排序时间复杂度为O(N*M),其中N为数据个数,M为数据位数。

辅助记忆

  • 时间复杂度记忆- 
    • 冒泡、选择、直接 排序需要两个for循环,每次只关注一个元素,平均时间复杂度为O(n2)O(n2)(一遍找元素O(n)O(n),一遍找位置O(n)O(n))
    • 快速、归并、希尔、堆基于二分思想,log以2为底,平均时间复杂度为O(nlogn)O(nlogn)(一遍找元素O(n)O(n),一遍找位置O(logn)O(logn))
  • 稳定性记忆-“快希选堆”(快牺牲稳定性) 
    • 排序算法的稳定性:排序前后相同元素的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。

原理理解

1 冒泡排序

1.1 过程

冒泡排序从小到大排序:一开始交换的区间为0~N-1,将第1个数和第2个数进行比较,前面大于后面,交换两个数,否则不交换。再比较第2个数和第三个数,前面大于后面,交换两个数否则不交换。依次进行,最大的数会放在数组最后的位置。然后将范围变为0~N-2,数组第二大的数会放在数组倒数第二的位置。依次进行整个交换过程,最后范围只剩一个数时数组即为有序。

1.2 动图

1.3 核心代码(函数)

<span style="color:#000000"><code class="language-C"><span style="color:#880000">//array[]为待排序数组,n为数组长度</span>
<span style="color:#000088">void</span> BubbleSort(<span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> n)
{
    <span style="color:#000088">int</span> i, j, k;
    <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>; i<n-<span style="color:#006666">1</span>; i++)
        <span style="color:#000088">for</span>(j=<span style="color:#006666">0</span>; j<n-<span style="color:#006666">1</span>-i; j++)
        {
            <span style="color:#000088">if</span>(<span style="color:#4f4f4f">array</span>[j]><span style="color:#4f4f4f">array</span>[j+<span style="color:#006666">1</span>])
            {
                k=<span style="color:#4f4f4f">array</span>[j];
                <span style="color:#4f4f4f">array</span>[j]=<span style="color:#4f4f4f">array</span>[j+<span style="color:#006666">1</span>];
                <span style="color:#4f4f4f">array</span>[j+<span style="color:#006666">1</span>]=k;
            }
        }
}</code></span>

2 选择排序

2.1 过程

选择排序从小到大排序:一开始从0~n-1区间上选择一个最小值,将其放在位置0上,然后在1~n-1范围上选取最小值放在位置1上。重复过程直到剩下最后一个元素,数组即为有序。

2.2 动图

 

2.3 核心代码(函数)

<span style="color:#000000"><code class="language-C"><span style="color:#880000">//array[]为待排序数组,n为数组长度</span>
<span style="color:#000088">void</span> selectSort(<span style="color:#000088">int</span> array[], <span style="color:#000088">int</span> n)
{
    <span style="color:#000088">int</span> i, j ,<span style="color:#4f4f4f">min</span> ,k;
    <span style="color:#000088">for</span>( i=<span style="color:#006666">0</span>; i<n-<span style="color:#006666">1</span>; i++)
    {
        <span style="color:#4f4f4f">min</span>=i; <span style="color:#880000">//每趟排序最小值先等于第一个数,遍历剩下的数</span>
        <span style="color:#000088">for</span>( j=i+<span style="color:#006666">1</span>; j<n; j++) <span style="color:#880000">//从i下一个数开始检查</span>
        {
            <span style="color:#000088">if</span>(array[<span style="color:#4f4f4f">min</span>]>array[j])
            {
                <span style="color:#4f4f4f">min</span>=j;
            }
        }
        <span style="color:#000088">if</span>(<span style="color:#4f4f4f">min</span>!=i)
        {
            k=array[<span style="color:#4f4f4f">min</span>];
            array[<span style="color:#4f4f4f">min</span>]=array[i];
            array[i]=k;
        }
    }
}</code></span>

3 插入排序

3.1 过程

插入排序从小到大排序:首先位置1上的数和位置0上的数进行比较,如果位置1上的数大于位置0上的数,将位置0上的数向后移一位,将1插入到0位置,否则不处理。位置k上的数和之前的数依次进行比较,如果位置K上的数更大,将之前的数向后移位,最后将位置k上的数插入不满足条件点,反之不处理。

3.2 动图

 

3.3 核心代码(函数)

<span style="color:#000000"><code class="language-C"><span style="color:#880000">//array[]为待排序数组,n为数组长度</span>
<span style="color:#000088">void</span> insertSort(<span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> n)
{
    <span style="color:#000088">int</span> i,j,temp;
    <span style="color:#000088">for</span>( i=<span style="color:#006666">1</span>;i<n;i++)
    {
        <span style="color:#000088">if</span>(<span style="color:#4f4f4f">array</span>[i]<<span style="color:#4f4f4f">array</span>[i-<span style="color:#006666">1</span>])
        {
            temp=<span style="color:#4f4f4f">array</span>[i];
            <span style="color:#000088">for</span>( j=i;<span style="color:#4f4f4f">array</span>[j-<span style="color:#006666">1</span>]>temp;j--)
            {
                <span style="color:#4f4f4f">array</span>[j]=<span style="color:#4f4f4f">array</span>[j-<span style="color:#006666">1</span>];
            }
            <span style="color:#4f4f4f">array</span>[j]=temp;
        }
    }
}</code></span>

4 归并排序

4.1 过程

归并排序从小到大排序:首先让数组中的每一个数单独成为长度为1的区间,然后两两一组有序合并,得到长度为2的有序区间,依次进行,直到合成整个区间。

4.2 动图

 

4.3 核心代码(函数)

  • 递归实现
<span style="color:#000000"><code class="language-C"><span style="color:#880000">////实现归并,并把数据都放在list1里面 </span>
<span style="color:#000088">void</span> merging(<span style="color:#000088">int</span> *list1, <span style="color:#000088">int</span> list1_size, <span style="color:#000088">int</span> *list2,  <span style="color:#000088">int</span> list2_size)
{
    <span style="color:#000088">int</span> i=<span style="color:#006666">0</span>, j=<span style="color:#006666">0</span>, k=<span style="color:#006666">0</span>, m=<span style="color:#006666">0</span>;
    <span style="color:#000088">int</span> temp[MAXSIZE];

    <span style="color:#000088">while</span>(i < list1_size && j < list2_size)
    {
        <span style="color:#000088">if</span>(list1[i]<list2[j])
        {
            temp[k++] = list1[i++];
        }
        <span style="color:#000088">else</span>
        {
            temp[k++] = list2[j++];
        }
    }
    <span style="color:#000088">while</span>(i<list1_size)
    {
        temp[k++] = list1[i++];
    }
    <span style="color:#000088">while</span>(j<list2_size)
    {
        temp[k++] = list2[j++];
    }

    <span style="color:#000088">for</span>(m=<span style="color:#006666">0</span>; m < (list1_size+list2_size); m++)
    {
        list1[m]=temp[m];
    }
}
<span style="color:#880000">//如果有剩下的,那么说明就是它是比前面的数组都大的,直接加入就可以了 </span>
<span style="color:#000088">void</span> mergeSort(<span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> n)
{
    <span style="color:#000088">if</span>(n><span style="color:#006666">1</span>)
    {
        <span style="color:#000088">int</span> *list1 = <span style="color:#4f4f4f">array</span>;
        <span style="color:#000088">int</span> list1_size = n/<span style="color:#006666">2</span>;
        <span style="color:#000088">int</span> *list2 = <span style="color:#4f4f4f">array</span> + n/<span style="color:#006666">2</span>;
        <span style="color:#000088">int</span> list2_size = n-list1_size;

        mergeSort(list1, list1_size);
        mergeSort(list2, list2_size);

        merging(list1, list1_size, list2, list2_size);
    }
}
<span style="color:#880000">//归并排序复杂度分析:一趟归并需要将待排序列中的所有记录  </span>
<span style="color:#880000">//扫描一遍,因此耗费时间为O(n),而由完全二叉树的深度可知,  </span>
<span style="color:#880000">//整个归并排序需要进行[log2n],因此,总的时间复杂度为  </span>
<span style="color:#880000">//O(nlogn),而且这是归并排序算法中平均的时间性能  </span>
<span style="color:#880000">//空间复杂度:由于归并过程中需要与原始记录序列同样数量级的  </span>
<span style="color:#880000">//存储空间去存放归并结果及递归深度为log2N的栈空间,因此空间  </span>
<span style="color:#880000">//复杂度为O(n+logN)  </span>
<span style="color:#880000">//也就是说,归并排序是一种比较占内存,但却效率高且稳定的算法 </span></code></span>
  • 迭代实现
<span style="color:#000000"><code class="language-C"><span style="color:#000088">void</span> MergeSort(<span style="color:#000088">int</span> k[],<span style="color:#000088">int</span> n)  
{  
    <span style="color:#000088">int</span> i,next,left_min,left_max,right_min,right_max;  
    <span style="color:#880000">//动态申请一个与原来数组一样大小的空间用来存储</span>
    <span style="color:#000088">int</span> *temp = (<span style="color:#000088">int</span> *)<span style="color:#4f4f4f">malloc</span>(n * <span style="color:#000088">sizeof</span>(<span style="color:#000088">int</span>));  
    <span style="color:#880000">//逐级上升,第一次比较2个,第二次比较4个,第三次比较8个。。。  </span>
    <span style="color:#000088">for</span>(i=<span style="color:#006666">1</span>; i<n; i*=<span style="color:#006666">2</span>)  
    {  
        <span style="color:#880000">//每次都从0开始,数组的头元素开始  </span>
        <span style="color:#000088">for</span>(left_min=<span style="color:#006666">0</span>; left_min<n-i; left_min = right_max)  
        {  
            right_min = left_max = left_min + i;  
            right_max = left_max + i;  
            <span style="color:#880000">//右边的下标最大值只能为n  </span>
            <span style="color:#000088">if</span>(right_max>n)  
            {  
                right_max = n;  
            }  
            <span style="color:#880000">//next是用来标志temp数组下标的,由于每次数据都有返回到K,  </span>
            <span style="color:#880000">//故每次开始得重新置零  </span>
            next = <span style="color:#006666">0</span>;  
            <span style="color:#880000">//如果左边的数据还没达到分割线且右边的数组没到达分割线,开始循环  </span>
            <span style="color:#000088">while</span>(left_min<left_max&&right_min<right_max)  
            {  
                <span style="color:#000088">if</span>(k[left_min] < k[right_min])  
                {  
                    temp[next++] = k[left_min++];  
                }  
                <span style="color:#000088">else</span>  
                {  
                    temp[next++] = k[right_min++];  
                }  
            }  
            <span style="color:#880000">//上面循环结束的条件有两个,如果是左边的游标尚未到达,那么需要把  </span>
            <span style="color:#880000">//数组接回去,可能会有疑问,那如果右边的没到达呢,其实模拟一下就可以  </span>
            <span style="color:#880000">//知道,如果右边没到达,那么说明右边的数据比较大,这时也就不用移动位置了  </span>

            <span style="color:#000088">while</span>(left_min < left_max)  
            {  
                <span style="color:#880000">//如果left_min小于left_max,说明现在左边的数据比较大  </span>
                <span style="color:#880000">//直接把它们接到数组的min之前就行  </span>
                k[--right_min] = k[--left_max];   
            }  
            <span style="color:#000088">while</span>(next><span style="color:#006666">0</span>)  
            {  
                <span style="color:#880000">//把排好序的那部分数组返回该k  </span>
                k[--right_min] = temp[--next];        
            }  
        }  
    }  
}  
<span style="color:#880000">//非递归的方法,避免了递归时深度为log2N的栈空间,</span>
<span style="color:#880000">//空间只是用到归并临时申请的跟原来数组一样大小的空间,并且在时间性能上也有一定的提升,</span>
<span style="color:#880000">//因此,使用归并排序是,尽量考虑用非递归的方法。</span></code></span>

5 快速排序

5.1 过程

快速排序从小到大排序:在数组中随机选一个数(默认数组首个元素),数组中小于等于此数的放在左边,大于此数的放在右边,再对数组两边递归调用快速排序,重复这个过程。

5.2 动图

 

5.3 核心代码(函数)

推荐程序(好理解)

<span style="color:#000000"><code class="language-C">//接口调整
void adjust_quicksort(int k[],int n)  
{  
   quicksort(k,<span style="color:#006666">0</span>,n-<span style="color:#006666">1</span>);  
}  
void quicksort(int a[], int left, int <span style="color:#009900">right</span>)  
{  
    int i,j,t,temp;  
    <span style="color:#000088">if</span>(left><span style="color:#009900">right</span>)  <span style="color:#880000"> //(递归过程先写结束条件)</span>
       <span style="color:#009900">return</span>;  

    temp=a[left];<span style="color:#880000"> //temp中存的就是基准数  </span>
    i=left;  
    j=<span style="color:#009900">right</span>;  
    <span style="color:#000088">while</span>(i!=j)  
    {  
                  <span style="color:#880000"> //顺序很重要,要先从右边开始找(最后交换基准时换过去的数要保证比基准小,因为基准                               </span>
                  <span style="color:#880000"> //选取数组第一个数,在小数堆中) </span>
                   <span style="color:#000088">while</span>(a[j]>=temp && i<j)  
                            j<span style="color:#880000">--;  </span>
                  <span style="color:#880000"> //再找右边的  </span>
                   <span style="color:#000088">while</span>(a[i]<=temp && i<j)  
                            i++;  
                  <span style="color:#880000"> //交换两个数在数组中的位置  </span>
                   <span style="color:#000088">if</span>(i<j)  
                   {  
                            t=a[i];  
                            a[i]=a[j];  
                            a[j]=t;  
                   }  
    }  
   <span style="color:#880000"> //最终将基准数归位 (之前已经temp=a[left]过了,交换只需要再进行两步)</span>
    a[left]=a[i];  
    a[i]=temp;  

    quicksort(left,i-<span style="color:#006666">1</span>)<span style="color:#880000">;//继续处理左边的,这里是一个递归的过程  </span>
    quicksort(i+<span style="color:#006666">1</span>,<span style="color:#009900">right</span>)<span style="color:#880000">;//继续处理右边的 ,这里是一个递归的过程  </span>
}  </code></span>

6 堆排序

6.1 过程

堆排序从小到大排序:首先将数组元素建成大小为n的大顶堆,堆顶(数组第一个元素)是所有元素中的最大值,将堆顶元素和数组最后一个元素进行交换,再将除了最后一个数的n-1个元素建立成大顶堆,再将最大元素和数组倒数第二个元素进行交换,重复直至堆大小减为1。

  • 注:完全二叉树 
    假设二叉树深度为n,除了第n层外,n-1层节点都有两个孩子,第n层节点连续从左到右。如下图 
    这里写图片描述

  • 注:大顶堆 
    大顶堆是具有以下性质的完全二叉树:每个节点的值都大于或等于其左右孩子节点的值。 
    即,根节点是堆中最大的值,按照层序遍历给节点从1开始编号,则节点之间满足如下关系: 
    这里写图片描述 (1<=i<=n/2)

6.2 动图

 
 

6.3 核心代码(函数)

这里写图片描述
注意!!!数组从1开始,1~n

<span style="color:#000000"><code class="language-c"><span style="color:#000088">void</span> heapSort(<span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> n)
{
    <span style="color:#000088">int</span> i;
    <span style="color:#000088">for</span> (i=n/<span style="color:#006666">2</span>;i><span style="color:#006666">0</span>;i--)
    {
        HeapAdjust(<span style="color:#4f4f4f">array</span>,i,n);<span style="color:#880000">//从下向上,从右向左调整</span>
    }
    <span style="color:#000088">for</span>( i=n;i><span style="color:#006666">1</span>;i--)
    {
        swap(<span style="color:#4f4f4f">array</span>, <span style="color:#006666">1</span>, i);
        HeapAdjust(<span style="color:#4f4f4f">array</span>, <span style="color:#006666">1</span>, i-<span style="color:#006666">1</span>);<span style="color:#880000">//从上到下,从左向右调整</span>
    }
}
<span style="color:#000088">void</span> HeapAdjust(<span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> s, <span style="color:#000088">int</span> n )
{
    <span style="color:#000088">int</span> i,temp;
    temp = <span style="color:#4f4f4f">array</span>[s];
    <span style="color:#000088">for</span>(i=<span style="color:#006666">2</span>*s;i<=n;i*=<span style="color:#006666">2</span>)
    {
        <span style="color:#000088">if</span>(i<n&&<span style="color:#4f4f4f">array</span>[i]<<span style="color:#4f4f4f">array</span>[i+<span style="color:#006666">1</span>])
        {
            i++;
        }
        <span style="color:#000088">if</span>(temp>=<span style="color:#4f4f4f">array</span>[i])
        {
            <span style="color:#000088">break</span>;
        }
        <span style="color:#4f4f4f">array</span>[s]=<span style="color:#4f4f4f">array</span>[i];
        s=i;
    }
    <span style="color:#4f4f4f">array</span>[s]=temp;
}
<span style="color:#000088">void</span> swap(<span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> i, <span style="color:#000088">int</span> j)
{
    <span style="color:#000088">int</span> temp;

    temp=<span style="color:#4f4f4f">array</span>[i];
    <span style="color:#4f4f4f">array</span>[i]=<span style="color:#4f4f4f">array</span>[j];
    <span style="color:#4f4f4f">array</span>[j]=temp;
}</code></span>

7 希尔排序

7.1 过程

希尔排序是插入排序改良的算法,希尔排序步长从大到小调整,第一次循环后面元素逐个和前面元素按间隔步长进行比较并交换,直至步长为1,步长选择是关键。

7.2 动图

这里写图片描述 

7.3 核心程序(函数)

<span style="color:#000000"><code class="language-c"><span style="color:#880000">//下面是插入排序</span>
<span style="color:#000088">void</span> InsertSort( <span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> n)
{
    <span style="color:#000088">int</span> i,j,temp;
    <span style="color:#000088">for</span>( i=<span style="color:#006666">0</span>;i<n;i++ )
    {
        <span style="color:#000088">if</span>(<span style="color:#4f4f4f">array</span>[i]<<span style="color:#4f4f4f">array</span>[i-<span style="color:#006666">1</span>])
        {
            temp=<span style="color:#4f4f4f">array</span>[i];
            <span style="color:#000088">for</span>( j=i-<span style="color:#006666">1</span>;<span style="color:#4f4f4f">array</span>[j]>temp;j--)
            {
                <span style="color:#4f4f4f">array</span>[j+<span style="color:#006666">1</span>]=<span style="color:#4f4f4f">array</span>[j];
            }
            <span style="color:#4f4f4f">array</span>[j+<span style="color:#006666">1</span>]=temp;
        }
    }
}
<span style="color:#880000">//在插入排序基础上修改得到希尔排序</span>
<span style="color:#000088">void</span> SheelSort( <span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> n)
{
    <span style="color:#000088">int</span> i,j,temp;
    <span style="color:#000088">int</span> gap=n; <span style="color:#880000">//~~~~~~~~~~~~~~~~~~~~~</span>
    <span style="color:#000088">do</span>{
        gap=gap/<span style="color:#006666">3</span>+<span style="color:#006666">1</span>;  <span style="color:#880000">//~~~~~~~~~~~~~~~~~~</span>
        <span style="color:#000088">for</span>( i=gap;i<n;i++ )
        {
            <span style="color:#000088">if</span>(<span style="color:#4f4f4f">array</span>[i]<<span style="color:#4f4f4f">array</span>[i-gap])
            {
                temp=<span style="color:#4f4f4f">array</span>[i];
                <span style="color:#000088">for</span>( j=i-gap;<span style="color:#4f4f4f">array</span>[j]>temp;j-=gap)
                {
                    <span style="color:#4f4f4f">array</span>[j+gap]=<span style="color:#4f4f4f">array</span>[j];
                }
                <span style="color:#4f4f4f">array</span>[j+gap]=temp;
            }
        }
    }<span style="color:#000088">while</span>(gap><span style="color:#006666">1</span>);  <span style="color:#880000">//~~~~~~~~~~~~~~~~~~~~~~</span>

}</code></span>

8 桶排序(基数排序和基数排序的思想)

8.1 过程

桶排序是计数排序的变种,把计数排序中相邻的m个”小桶”放到一个”大桶”中,在分完桶后,对每个桶进行排序(一般用快排),然后合并成最后的结果。

8.2 图解

8.3 核心程序

<span style="color:#000000"><code class="language-c"><span style="color:#009900">#include <stdio.h></span>
<span style="color:#000088">int</span> main()
{
    <span style="color:#000088">int</span> a[<span style="color:#006666">11</span>],i,j,t;
    <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>;i<=<span style="color:#006666">10</span>;i++)
        a[i]=<span style="color:#006666">0</span>;  <span style="color:#880000">//初始化为0</span>

    <span style="color:#000088">for</span>(i=<span style="color:#006666">1</span>;i<=<span style="color:#006666">5</span>;i++)  <span style="color:#880000">//循环读入5个数</span>
    {
        <span style="color:#4f4f4f">scanf</span>(<span style="color:#009900">"%d"</span>,&t);  <span style="color:#880000">//把每一个数读到变量t中</span>
        a[t]++;  <span style="color:#880000">//进行计数(核心行)</span>
    }

    <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>;i<=<span style="color:#006666">10</span>;i++)  <span style="color:#880000">//依次判断a[0]~a[10]</span>
        <span style="color:#000088">for</span>(j=<span style="color:#006666">1</span>;j<=a[i];j++)  <span style="color:#880000">//出现了几次就打印几次</span>
            <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"%d "</span>,i);

    getchar();getchar(); 
    <span style="color:#880000">//这里的getchar();用来暂停程序,以便查看程序输出的内容</span>
    <span style="color:#880000">//也可以用system("pause");等来代替</span>
    <span style="color:#000088">return</span> <span style="color:#006666">0</span>;
}</code></span>

9 计数排序

9.1 过程

算法的步骤如下: 
- 找出待排序的数组中最大和最小的元素 
- 统计数组中每个值为i的元素出现的次数,存入数组C的第i项 
- 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加) 
- 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

9.2 图解

这里写图片描述

9.3 核心程序(函数)

<span style="color:#000000"><code class="language-c">程序<span style="color:#006666">1</span>:
<span style="color:#009900">#define NUM_RANGE (100)    <span style="color:#009900">//预定义数据范围上限,即K的值</span></span>

<span style="color:#000088">void</span> counting_sort(<span style="color:#000088">int</span> *ini_arr, <span style="color:#000088">int</span> *sorted_arr, <span style="color:#000088">int</span> n)  <span style="color:#880000">//所需空间为 2*n+k</span>
{  
       <span style="color:#000088">int</span> *count_arr = (<span style="color:#000088">int</span> *)<span style="color:#4f4f4f">malloc</span>(<span style="color:#000088">sizeof</span>(<span style="color:#000088">int</span>) * NUM_RANGE);  
       <span style="color:#000088">int</span> i, j, k;  

       <span style="color:#880000">//初始化统计数组元素为值为零 </span>
       <span style="color:#000088">for</span>(k=<span style="color:#006666">0</span>; k<NUM_RANGE; k++){  
               count_arr[k] = <span style="color:#006666">0</span>;  
       }  
       <span style="color:#880000">//统计数组中,每个元素出现的次数    </span>
       <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>; i<n; i++){  
               count_arr[ini_arr[i]]++;  
       }  

       <span style="color:#880000">//统计数组计数,每项存前N项和,这实质为排序过程</span>
       <span style="color:#000088">for</span>(k=<span style="color:#006666">1</span>; k<NUM_RANGE; k++){  
               count_arr[k] += count_arr[k-<span style="color:#006666">1</span>];  
       }  

       <span style="color:#880000">//将计数排序结果转化为数组元素的真实排序结果</span>
       <span style="color:#000088">for</span>(j=n-<span style="color:#006666">1</span> ; j>=<span style="color:#006666">0</span>; j--){  
           <span style="color:#000088">int</span> elem = ini_arr[j];          <span style="color:#880000">//取待排序元素</span>
           <span style="color:#000088">int</span> index = count_arr[elem]-<span style="color:#006666">1</span>;  <span style="color:#880000">//待排序元素在有序数组中的序号</span>
           sorted_arr[index] = elem;       <span style="color:#880000">//将待排序元素存入结果数组中</span>
           count_arr[elem]--;              <span style="color:#880000">//修正排序结果,其实是针对算得元素的修正</span>
       }  
       <span style="color:#4f4f4f">free</span>(count_arr);  
}  

程序<span style="color:#006666">2</span>:C++(最大最小压缩桶数)
<span style="color:#000088">public</span> <span style="color:#000088">static</span> <span style="color:#000088">void</span> countSort(<span style="color:#000088">int</span>[] arr) {
        <span style="color:#000088">if</span> (arr == null || arr.length < <span style="color:#006666">2</span>) {
            <span style="color:#000088">return</span>;
        }
        <span style="color:#000088">int</span> min = arr[<span style="color:#006666">0</span>];
        <span style="color:#000088">int</span> max = arr[<span style="color:#006666">0</span>];
        <span style="color:#000088">for</span> (<span style="color:#000088">int</span> i = <span style="color:#006666">1</span>; i < arr.length; i++) {
            min = Math.min(arr[i], min);
            max = Math.max(arr[i], max);
        }
        <span style="color:#000088">int</span>[] countArr = <span style="color:#000088">new</span> <span style="color:#000088">int</span>[max - min + <span style="color:#006666">1</span>];
        <span style="color:#000088">for</span> (<span style="color:#000088">int</span> i = <span style="color:#006666">0</span>; i < arr.length; i++) {
            countArr[arr[i] - min]++;
        }
        <span style="color:#000088">int</span> index = <span style="color:#006666">0</span>;
        <span style="color:#000088">for</span> (<span style="color:#000088">int</span> i = <span style="color:#006666">0</span>; i < countArr.length; i++) {
            <span style="color:#000088">while</span> (countArr[i]-- > <span style="color:#006666">0</span>) {
                arr[index++] = i + min;
        }
}</code></span>

10 基数排序

10.1 过程

基数排序是基于数据位数的一种排序算法。 
它有两种算法 
①LSD–Least Significant Digit first 从低位(个位)向高位排。 
②MSD– Most Significant Digit first 从高位向低位(个位)排。 
时间复杂度O(N*最大位数)。 
空间复杂度O(N)。

10.2 图解

这里写图片描述 
对a[n]按照个位0~9进行桶排序: 
这里写图片描述 
对b[n]进行累加得到c[n],用于b[n]中重复元素计数 
!!!b[n]中的元素为temp中的位置!!!跳跃的用++补上: 
这里写图片描述 
temp数组为排序后的数组,写回a[n]。temp为按顺序倒出桶中的数据(联合b[n],c[n],a[n]得到),重复元素按顺序输出: 
这里写图片描述

10.3 核心程序

<span style="color:#000000"><code class="language-c"><span style="color:#880000">//基数排序  </span>
<span style="color:#880000">//LSD  先以低位排,再以高位排  </span>
<span style="color:#880000">//MSD  先以高位排,再以低位排  </span>
<span style="color:#000088">void</span> LSDSort(<span style="color:#000088">int</span> *a, <span style="color:#000088">int</span> n)  
{  
    assert(a);  <span style="color:#880000">//判断a是否为空,也可以a为空||n<2返回</span>
    <span style="color:#000088">int</span> digit = <span style="color:#006666">0</span>;   <span style="color:#880000">//最大位数初始化</span>
    <span style="color:#000088">for</span> (<span style="color:#000088">int</span> i = <span style="color:#006666">0</span>; i < n; ++i)  
    {   <span style="color:#880000">//求最大位数</span>
        <span style="color:#000088">while</span> (a[i] > (<span style="color:#4f4f4f">pow</span>(<span style="color:#006666">10</span>,digit)))  <span style="color:#880000">//pow函数要包含头文件math.h,pow(10,digit)=10^digit</span>
        {  
            digit++;  
        }  
    }  
    <span style="color:#000088">int</span> flag = <span style="color:#006666">1</span>;   <span style="color:#880000">//位数</span>
    <span style="color:#000088">for</span> (<span style="color:#000088">int</span> j = <span style="color:#006666">1</span>; j <= digit; ++j)  
    {  
        <span style="color:#880000">//建立数组统计每个位出现数据次数(Digit[n]为桶排序b[n])  </span>
        <span style="color:#000088">int</span> Digit[<span style="color:#006666">10</span>] = { <span style="color:#006666">0</span> };  
        <span style="color:#000088">for</span> (<span style="color:#000088">int</span> i = <span style="color:#006666">0</span>; i < n; ++i)  
        {  
            Digit[(a[i] / flag)%<span style="color:#006666">10</span>]++;  <span style="color:#880000">//flag=1时为按个位桶排序</span>
        }  
         <span style="color:#880000">//建立数组统计起始下标(BeginIndex[n]为个数累加c[n],用于记录重复元素位置</span>
         <span style="color:#880000">//flag=1时,下标代表个位数值,数值代表位置,跳跃代表重复)</span>
        <span style="color:#000088">int</span> BeginIndex[<span style="color:#006666">10</span>] = { <span style="color:#006666">0</span> };  
        <span style="color:#000088">for</span> (<span style="color:#000088">int</span> i = <span style="color:#006666">1</span>; i < <span style="color:#006666">10</span>; ++i)  
        {  
            <span style="color:#880000">//累加个数</span>
            BeginIndex[i] = BeginIndex[i - <span style="color:#006666">1</span>] + Digit[i - <span style="color:#006666">1</span>];  
        }  
        <span style="color:#880000">//建立辅助空间进行排序 </span>
        <span style="color:#880000">//下面两条可以用calloc函数实现</span>
        <span style="color:#000088">int</span> *tmp = <span style="color:#000088">new</span> <span style="color:#000088">int</span>[n];  
        <span style="color:#4f4f4f">memset</span>(tmp, <span style="color:#006666">0</span>, <span style="color:#000088">sizeof</span>(<span style="color:#000088">int</span>)*n);<span style="color:#880000">//初始化  </span>
        <span style="color:#880000">//联合各数组求排序后的位置存在temp中</span>
        <span style="color:#000088">for</span> (<span style="color:#000088">int</span> i = <span style="color:#006666">0</span>; i < n; ++i)  
        {  
            <span style="color:#000088">int</span> index = (a[i] / flag)%<span style="color:#006666">10</span>;  <span style="color:#880000">//桶排序和位置数组中的下标</span>
            <span style="color:#880000">//计算temp相应位置对应a[i]中的元素,++为BeginIndex数组数值加1</span>
            <span style="color:#880000">//跳跃间隔用++来补,先用再++</span>
            tmp[BeginIndex[index]++] = a[i];  
        }  
        <span style="color:#880000">//将数据重新写回原空间  </span>
        <span style="color:#000088">for</span> (<span style="color:#000088">int</span> i = <span style="color:#006666">0</span>; i < n; ++i)  
        {  
            a[i] = tmp[i];  
        }  
        flag = flag * <span style="color:#006666">10</span>;  
        <span style="color:#000088">delete</span>[] tmp;  
    }  
}  </code></span>

附:

1 完整程序框架(冒泡排序举例)

1.1 VS2010程序

<span style="color:#000000"><code class="language-c"><span style="color:#009900">#include "stdafx.h"</span>
<span style="color:#009900">#include "stdio.h"</span>
<span style="color:#009900">#include <stdlib.h></span>

<span style="color:#000088">void</span> BubbleSort(<span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> n){
    <span style="color:#000088">int</span> i,j,k,count1=<span style="color:#006666">0</span>, count2=<span style="color:#006666">0</span>;
    <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>; i<n-<span style="color:#006666">1</span>; i++)
        <span style="color:#000088">for</span>(j=n-<span style="color:#006666">1</span>; j>i; j--)
        {
            count1++;
            <span style="color:#000088">if</span>(<span style="color:#4f4f4f">array</span>[j-<span style="color:#006666">1</span>]><span style="color:#4f4f4f">array</span>[j])
            {
                count2++;
                k=<span style="color:#4f4f4f">array</span>[j-<span style="color:#006666">1</span>];
                <span style="color:#4f4f4f">array</span>[j-<span style="color:#006666">1</span>]=<span style="color:#4f4f4f">array</span>[j];
                <span style="color:#4f4f4f">array</span>[j]=k;
            }
        }
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"总共的循环次序为:%d,  总共的交换次序为:%d\n\n"</span>, count1, count2);
}


<span style="color:#000088">int</span> main(<span style="color:#000088">int</span> argc, _TCHAR* argv[])
{
    <span style="color:#000088">int</span> as[]={<span style="color:#006666">0</span>,<span style="color:#006666">1</span>,<span style="color:#006666">2</span>,<span style="color:#006666">3</span>,<span style="color:#006666">4</span>,<span style="color:#006666">6</span>,<span style="color:#006666">8</span>,<span style="color:#006666">5</span>,<span style="color:#006666">9</span>,<span style="color:#006666">7</span>};
    BubbleSort(as, <span style="color:#006666">10</span>);
    <span style="color:#000088">for</span>(<span style="color:#000088">int</span> i=<span style="color:#006666">0</span>; i<<span style="color:#006666">10</span>; i++)
    {
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"%d"</span>, as[i]);
    }
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"\n\n"</span>);
    system(<span style="color:#009900">"pause"</span>);
    <span style="color:#000088">return</span> <span style="color:#006666">0</span>;
}</code></span>

1.2 执行程序(OJ)

<span style="color:#000000"><code class="language-c"><span style="color:#009900">#include <stdio.h></span>

<span style="color:#000088">void</span> BubbleSort(<span style="color:#000088">int</span> <span style="color:#4f4f4f">array</span>[], <span style="color:#000088">int</span> n){
    <span style="color:#000088">int</span> i,j,k,count1=<span style="color:#006666">0</span>, count2=<span style="color:#006666">0</span>;
    <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>; i<n-<span style="color:#006666">1</span>; i++)
        <span style="color:#000088">for</span>(j=n-<span style="color:#006666">1</span>; j>i; j--)
        {
            count1++;
            <span style="color:#000088">if</span>(<span style="color:#4f4f4f">array</span>[j-<span style="color:#006666">1</span>]><span style="color:#4f4f4f">array</span>[j])
            {
                count2++;
                k=<span style="color:#4f4f4f">array</span>[j-<span style="color:#006666">1</span>];
                <span style="color:#4f4f4f">array</span>[j-<span style="color:#006666">1</span>]=<span style="color:#4f4f4f">array</span>[j];
                <span style="color:#4f4f4f">array</span>[j]=k;
            }
        }
    <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"总共的循环次序为:%d,  总共的交换次序为:%d\n\n"</span>, count1, count2);
}

<span style="color:#000088">int</span> main()
{
    <span style="color:#000088">int</span> as[]={<span style="color:#006666">0</span>,<span style="color:#006666">1</span>,<span style="color:#006666">2</span>,<span style="color:#006666">3</span>,<span style="color:#006666">4</span>,<span style="color:#006666">6</span>,<span style="color:#006666">8</span>,<span style="color:#006666">5</span>,<span style="color:#006666">9</span>,<span style="color:#006666">7</span>};
    BubbleSort(as, <span style="color:#006666">10</span>);
    <span style="color:#000088">int</span> i=<span style="color:#006666">0</span>;
    <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>; i<<span style="color:#006666">10</span>; i++)
    {
        <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"%d"</span>, as[i]);
    }
    <span style="color:#000088">return</span> <span style="color:#006666">0</span>;
}</code></span>

2 关于交换的优化

不用中间变量进行交换

<span style="color:#000000"><code class="language-c"><span style="color:#000088">if</span>(A[j] <= A[i]){
    A[j] = A[j] + A[i];
    A[i] = A[j] - A[i];
    A[j] = A[j] - A[i];
}</code></span>

3 C语言实现数组动态输入

<span style="color:#000000"><code class="language-c"><span style="color:#009900">#include <stdio.h>  </span>
<span style="color:#009900">#include <assert.h>  <span style="color:#009900">//断言头文件</span></span>
<span style="color:#009900">#include <stdlib.h>  </span>

<span style="color:#000088">int</span> main(<span style="color:#000088">int</span> argc, <span style="color:#000088">char</span> <span style="color:#000088">const</span> *argv[])  
{  
    <span style="color:#000088">int</span> size = <span style="color:#006666">0</span>;  
    <span style="color:#4f4f4f">scanf</span>(<span style="color:#009900">"%d"</span>, &size);   <span style="color:#880000">//首先输入数组个数</span>
    assert(size > <span style="color:#006666">0</span>);     <span style="color:#880000">//判断数组个数是否非法</span>

    <span style="color:#000088">int</span> *<span style="color:#4f4f4f">array</span> = (<span style="color:#000088">int</span> *)<span style="color:#4f4f4f">calloc</span>(size, <span style="color:#000088">sizeof</span>(<span style="color:#000088">int</span>));  <span style="color:#880000">//动态分配数组</span>
    <span style="color:#000088">if</span>(!R1)  
    {  
        <span style="color:#000088">return</span>;           <span style="color:#880000">//申请空间失败  </span>
    }  

    <span style="color:#000088">int</span> i = <span style="color:#006666">0</span>;  
    <span style="color:#000088">for</span> (i = <span style="color:#006666">0</span>; i < size; ++i) {  
        <span style="color:#4f4f4f">scanf</span>(<span style="color:#009900">"%d"</span>, &<span style="color:#4f4f4f">array</span>[i]);  
    }  

    mergeSort(<span style="color:#4f4f4f">array</span>, size);  
    printArray(<span style="color:#4f4f4f">array</span>, size);  

    <span style="color:#4f4f4f">free</span>(<span style="color:#4f4f4f">array</span>);  
    <span style="color:#000088">return</span> <span style="color:#006666">0</span>;  
} </code></span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值