c 排序 汇总

link网址为大神的图解分析,有助于理解各种排序算法。

/*
 * 所有排序均为升序排列
 * 图解分析可参考:http://www.cnblogs.com/skywang12345/p/3603935.html
 */
#include <stdio.h>
#include <stdlib.h>
#define LEN(array) (sizeof(array)/sizeof(array[0]))
#define swap(a,b) (a^=b,b^=a,a^=b)
/**打印数组元素**/
void print_array(int arr[], int arr_length)
{
    int i;
    for(i=0;i<arr_length;i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
}

/**冒泡排序
**link:http://ahalei.blog.51cto.com/4767671/1364401
**link:http://www.cnblogs.com/skywang12345/p/3596232.html
** 一次循环冒出一个,最多n-1次循环即可结束。
** 对冒泡排序进行优化,使它效率更高一些:添加一个标记,如果一趟遍历中发生了交换,则
** 标记为true,否则为false。如果某一趟没有发生交换,说明排序已经完成!

** 冒泡排序的时间复杂度是O(N2)。
** 冒泡排序是稳定的算法,它满足稳定算法的定义。
**/
void bubble_sort(int arr[], int arr_length)
{
    int i,j;
    int flag;
    for(j = 0; j < arr_length-1; j++)
    {
        flag = 0;
        for(i = 0; i < arr_length-j-1; i++)
        {
            if(arr[i] > arr[i+1])
            {
                swap(arr[i], arr[i+1]);    /*交换,大的往后移动*/
                flag = 1;
            }
        }
        if(0 == flag){
            break;
        }
    }
}

/**插入排序
**link:http://www.cnblogs.com/fzhe/archive/2013/01/25/2871699.html
**
**直接插入排序的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表。
**开始时有序表中只包含1个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,
**将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。
**
**关键的两句话:1.元素拿出来;2.符合条件的后移
**直接插入排序的时间复杂度是O(N2)。
**直接插入排序是稳定的算法,它满足稳定算法的定义。
**/
void insert_sort(int arr[], int arr_length)
{
    int i,j,temp;
    for(i=1;i<arr_length;i++)
    {
        temp=arr[i];
        j=i-1;  
        while(j>=0 && temp<arr[j])
        {
            arr[j+1]=arr[j]; /* 将关键字大于a[i]的记录后移 */
            j--;
        }
        arr[j+1]=temp;
    }
}

/**希尔排序(直接插入排序的改进)
 **link:http://www.cnblogs.com/skywang12345/p/3603935.html
 **希尔排序实质上是一种分组插入方法。它的基本思想是:对于n个待排序的数列,
 **取一个小于n的整数gap(gap被称为步长)将待排序元素分成若干个组子序列,
 **所有距离为gap的倍数的记录放在同一个组中;然后,对各组内的元素进行直接插入排序。
 **这一趟排序完成之后,每一个组的元素都是有序的。然后减小gap的值,并重复执行上述的分组和排序。
 **重复这样的操作,当gap=1时,整个数列就是有序的。

 **希尔排序的时间复杂度与增量(即,步长gap)的选取有关
 **希尔排序是不稳定的算法,它满足稳定算法的定义。
 **业界测试:gap = gap/3+1
 **/
void shell_sort(int arr[], int arr_length)
{
    int i,j,gap,temp; 
    gap=arr_length/2; /*间距值*/ 
    while(gap>=1) 
    { 
        for(i=gap;i<arr_length;i++) 
        { 
            temp=arr[i]; 
            j=i-gap; 
            while(j>=0 && temp<arr[j]) 
            { 
                arr[j+gap]=arr[j]; 
                j-=gap; 
            } 
            arr[j+gap]=temp; 
        } 
        gap/=2; /*缩小间距值*/ 
    } 
}

/**快速排序
**link:http://ahalei.blog.51cto.com/4767671/1365285
**link:http://www.cnblogs.com/skywang12345/p/3596746.html
**快速排序(Quick Sort)使用分治法策略。
**它的基本思想是:选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;
**其中一部分的所有数据都比另外一部分的所有数据都要小。然后,再按此方法对这两部分数据分别进行快速排序,
**整个排序过程可以递归进行,以此达到整个数据变成有序序列。

**快速排序是不稳定的算法,它不满足稳定算法的定义。
**快速排序的时间复杂度在最坏情况下是O(N2),平均的时间复杂度是O(N*lgN)。
**/
void quick_sort(int arr[], int left, int right)
{
    int i,j,temp;
    if(left>=right)
       return;
    temp = arr[left];  //temp中存的就是基准数
    i = left;
    j = right;
    while(i != j)
    {
        //先从右边开始找 第一个 小于temp的数
        while(arr[j] >= temp && i<j )
        {
            j--;
        }
        //再找左边的 第一个 大于temp的数
        while(arr[i] <= temp && i<j)
        {
            i++;
        }
        //交换两个数在数组中的位置
        if(i<j)
        {
            swap(arr[i], arr[j]);
        }
    }
    //最终将基准数归位
    arr[left] = arr[i];
    arr[i]= temp;

    quick_sort(arr,left,i-1);  //继续处理左边的,这里是一个递归的过程
    quick_sort(arr,i+1,right);   //继续处理右边的 ,这里是一个递归的过程
}


/**选择排序
 **link:http://www.cnblogs.com/skywang12345/p/3597641.html
 **选择排序(Selection sort)是一种简单直观的排序算法。
 **它的基本思想是:首先在未排序的数列中找到最小(or最大)元素,然后将其存放到数列的起始位置;
 **接着,再从剩余未排序的元素中继续寻找最小(or最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
 **
 **选择排序的时间复杂度是O(N*N)
 **选择排序是稳定的算法,它满足稳定算法的定义。
 **/
void select_sort(int arr[], int arr_length)
{
    int i,j,min;
    for(i = 0; i < arr_length; i++)
    {
        min = i;
        //找出"a[i+1] ... a[n]"之间的最小元素,并赋值给min。
        for(j = i+1; j < arr_length; j++)
        {
            if(arr[j]<arr[min])
            {
                min=j; 
            }
        }   
         // 若min!=i,则交换 a[i] 和 a[min],交换之后,保证了a[0] ... a[i] 之间的元素是有序的。
        if(min!=i)
        { 
            swap(arr[i], arr[min]);
        } 
    } 
}

/**堆排序
 **link:http://www.cnblogs.com/skywang12345/p/3602162.html
 **最大堆进行升序排序的基本思想:
 **① 初始化堆:将数列a[1...n]构造成最大堆。
 **② 交换数据:将a[1]和a[n]交换,使a[n]是a[1...n]中的最大值;然后将a[1...n-1]重新调整为最大堆。 
 **接着,将a[1]和a[n-1]交换,使a[n-1]是a[1...n-1]中的最大值;然后将a[1...n-2]重新调整为最大值。
 **依次类推,直到整个数列都是有序的。
 **/
//(最大)堆的向下调整算法(调整为最大堆)
void maxheap_down(int a[], int start, int end)
{

    int c=start;     // 当前(current)节点的位置
    int l=2*c+1;     // 左(left)孩子的位置
    int tmp=a[c];    // 当前(current)节点的大小
    for( ; l<=end; c=l,l=2*l+1){
         // "l"是左孩子,"l+1"是右孩子  // 左右两孩子中选择较大者
        if(l<end && a[l] < a[l+1])
        {
            l++;
        }
        if(tmp >= a[l])
        {
            break;    // 调整结束
        }
        else
        {
            a[c]=a[l];
            a[l]=tmp;
        }
    }
}
//堆排序(小到大)
void heap_sort(int arr[], int arr_length)
{
    int i;
    // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。
    for(i=arr_length/2-1;i>=0;i--)
    {
        maxheap_down(arr,i,arr_length-1);
    }
    for(i=arr_length-1;i>0;i--)
    {
        swap(arr[0], arr[i]);  // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。
        maxheap_down(arr,0,i-1);  // 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
    }
}
/**归并排序
 **link:http://www.cnblogs.com/skywang12345/p/3602369.html
 **将待排序的数列分成若干个长度为1的子数列,然后将这些数列两两合并;得到若干个长度为2的有序数列,
 **再将这些数列两两合并;得到若干个长度为4的有序数列,再将它们两两合并;直接合并成一个数列为止。
 **/

//2. 将一个数组中的两个相邻有序区间合并成一个(合)
void Merge(int a[],int low,int mid,int high)  
{
    int *arr;
    int i,j,p;
    i = low;
    j = mid+1;
    p = 0;
    arr = (int *)malloc((high-low+1)*sizeof(int));//申请空间 临时存放数据
    if(NULL == arr)
    {
        fprintf(stderr,"malloc fault");
    }
    while(i<=mid && j<=high)
    {
        arr[p++] = (a[i]<a[j])?a[i++]:a[j++];// 在两个有序区间内选择小的存放在临时数组中
        //arr[p] = (a[i]<a[j])?a[i]:a[j];// 在两个有序区间内选择小的存放在临时数组中
        //p++;
        //i++;
        //j++;
    }
    while(i<=mid)  //剩下左边的,全部拿过来
    {
        arr[p++] = a[i++];
    }
    while(j<=high) //剩下右边的,全部拿过来
    {
        arr[p++] = a[j++];
    }

    for(i=low,p=0;i<=high;i++,p++)
    {
        a[i] = arr[p];//复制到之前的数据中
    }
    free(arr);//释放空间
}
//1. 先将原来的数据表分成排好序的子表(拆)
void merge_sort(int arr[],int low,int high)
{
    //用分治法对a[low..high]进行二路归并排序 
    int mid;
    if(low<high)
    {
        mid = (low+high)/2;
        merge_sort(arr,low,mid);    //递归地对a[low..mid]排序  
        merge_sort(arr,mid+1,high); //递归地对a[mid+1..high]排序 
        Merge(arr,low,mid,high);    //组合,将两个有序区归并为一个有序区  
    }
}
/**基数排序
 **link:http://www.cnblogs.com/skywang12345/p/3603669.html
 **link:http://blog.csdn.net/tjyyyangyi/article/details/7969381
 **基数排序(Radix Sort)是桶排序的扩展,它的基本思想是:将整数按位数切割成不同的数字,然后按每个位数分别比较。
 **/
void radix_sort(int arr[], int arr_length)
{

    int **temp;
    int i,j;
    int order[10]={0};   //存放个位、十位、百位、0~9 出现的次数
    int k;  //k表示当前比较的那一位上的具体数字
    int n; //n=1,10,100,1000...取决于a中的最大的数
    int p; //排列好的数组的下标
    temp = (int**)malloc(sizeof(int)*10);//为二维数组分配row行  10
    for (i = 0; i < 10; i++)
    {
        //分配列空间,列数为   arr_length
        temp[i] = (int*)malloc(sizeof(int)*arr_length);
    }
    //int temp[10][6]={0}; //第一个10表示0~9,第二个数为数组元素个数,其实不用取那么大,以防万一。
    n=1;    
    while(n <= 100)
    {
        for(i=0;i<arr_length;i++)
        {
            k = (arr[i]/n) % 10;//k代表取a[i]的哪位: n=1取个位,n=10;取十位,n=100,取百位。
            temp[k][order[k]] = arr[i];
            order[k]++;
        }   
        p=0; //p为完成一次排序过程中,a的下标
        for(i=0;i<10;i++)//这里的10 是根据0~9定的
        {
            if(order[i] != 0)
            {
                for(j=0;j<order[i];j++)
                {
                    arr[p++] = temp[i][j];
                }
                order[i] = 0;
            }
        }   
        n*= 10;//依次 个位、十位、百位
    }
     //释放动态开辟的空间
    for (i = 0; i < 10; i++)
    {
        free(temp[i]);
    }
    free(temp);
}

int main(){
    int array[] = {30,40,60,10,20,50};
    int len = LEN(array);

    //bubble_sort(array, len);
    //printf("1.冒泡排序:\n");

    //insert_sort(array, len);
    //printf("2.插入排序:\n");

    //quick_sort(array, 0, len-1);
    //printf("3.快速排序:\n");

    //shell_sort(array, len);
    //printf("4.希尔排序:\n");

    //select_sort(array, len);
    //printf("5.选择排序:\n");

    //heap_sort(array, len);
    //printf("6.堆排序:\n");

    merge_sort(array, 0, len-1);
    printf("7.归并排序:\n");

    //radix_sort(array, len);
    //printf("8.基数排序:\n");

    print_array(array, len);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值