用C语言实现常用排序算法

插入排序

概述:

有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为⊙(㎡)。是稳定的排序方法。
  插入算法(insertion sort)把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外,而第二部分就只包含这一个元素。在第一部分排序后,再把这个最后元素插入到此刻已是有序的第一部分里的正确位置中。

包括:直接插入排序,折半插入排序,链表插入排序,Shell排序

算法基本原理:

假定这个数组的序是排好的,然后从头往后,如果有数比当前外层元素的值大,则将这个数的位置往后挪,直到当前外层元素的值大于或等于它前面的位置为止.这具算法在排完前k个数之后,可以保证a[1…k]是局部有序的,保证了插入过程的正确性.

算法描述:
  一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置中
  6. 重复步骤2
  如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。

算法实现:

void insertSort()
{
    int array[] = {9,43,567,1,45,23,123,54,234,987};
    int length = sizeof(array)/sizeof(array[0]);
    int i,j,t,m;
    //插入排序开始
    for(i=1;i<length;i++)//默认下标为0的已经是排序好的,所以从1开始
    {
        t = array[i];
        j=i;
        while((j>0)&&(array[j-1]>t))//如果前面的数比它大交换之
        {
            m=array[j-1];
            array[j-1]=array[j];
            array[j]=m;
            j--;//交换完毕继续比较
        }
    }
    //插入排序结束
    for(i=0;i<length;i++)
    {
        printf("%d \n",array[i]);
    }
}

希尔排序

希尔排序是基于插入排序的一种算法,在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度为 O(N(logN)2), 没有快速排序算法快 O(N(logN)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(N2)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家门提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法. 本质上讲,希尔排序算法的一种改进,减少了其复制的次数,速度要快很多。原因是,当N值很大时数据项每一趟排序需要的个数很少,但数据项的距离很长。当N值减小时每一趟需要和动的数据增多,此时已经接近于它们排序后的最终位置。正是这两种情况的结合才使希尔排序效率比插入排序高很多。

在直接插入排序算法中,每次插入一个数,使有序序列只增加1个节点,并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
下面的函数是一个希尔排序算法的一个实现,初次取序列的一半为增量,
以后每次减半,直到增量为1。
希尔排序是不稳定的。

void shellSort()
{
    int array[] = {1,445,754,77,35,123,754,876,54,3};
    int length = sizeof(array)/sizeof(array[0]);
    int i,j,k,t,m;
    
    for(i=length/2;i>0;i=i/2)//控制增量
    {
        for(j=i;j<length;j++)//下面的就是直插排序
        {
            t = array[j];
            for(k=j-i;(k>=0 && t<array[k]);k=k-i)
            {
                m = array[k+i];
                array[k+i]=array[k];
                array[k]=m;
            }
            array[k+i]=t;
        }
    }
    for(i=0;i<length;i++)
    {
        printf("%d \n",array[i]);
    }
}

冒泡排序

算法基本原理:

对尚未排序的各元素从头到尾依次比较相邻的两个元素是否逆序(与欲排顺序相反),若逆序就交换这两元素,经过第一轮比较排序后便可把最大(或最小)的元素排好,然后再用同样的方法把剩下的元素逐个进行比较,就得到了你所要的顺序。

算法实现:

方法一:

void bubbleSort1()
{
    int array[10] = {1,2,11,22,33,4,23,234,4,6};
    int length = sizeof(array)/sizeof(array[0]);
    int flag = 0;
    for(int i=0; i<length-1; i++)
    {
        for(int j=0; j<length-1-i; j++)
        {
            if(array[j]>array[j+1])
            {
                flag = 1;
                array[j] = array[j] + array[j+1];
                array[j+1] = array[j] - array[j+1];
                array[j] = array[j] - array[j+1];
            }
        }
        if(flag == 0) break;
    }
    
    //冒泡排序结束,输出显示排序的结果
    for(int i=0; i<length; i++)
    {
        printf("%d \n",array[i]);
    }
}


方法二(优化):

//冒泡排序,开始的时候两个数进行比较,大的向后小的向前,第一次比较很容易的就把最大的一个数字放到了最后小的呢,继续向前,第二次当然也找到了第二个大的,放到倒数第二的位置,如此下去便可。这个是优化的冒泡排序方法,让k=j保存最后的那个数的下标,这样k后面的数都是排序好的了,这个排序是稳定的,时间复杂度是N平方
void bubbleSort2()
{
    int array[10] = {1,2,11,22,33,4,23,234,4,6};
    int length = sizeof(array)/sizeof(array[0]);
    int k=0, s=0, i=0, j=0, m=0;
    //冒泡排序开始
    for(i = length-1;i>0;i=k)
    {
        for(j=0, k=0;j<i;j++)
        {
            if(array[j]>array[j+1])//把比较出来大的数据向后移动
            {
                m=array[j];
                array[j]=array[j+1];
                array[j+1]=m;
                k=j;
            }
        }
    }
    //冒泡排序结束,输出显示排序的结果
    for(s=0; s<length; s++)
    {
        printf("%d \n",array[s]);
    }
}

快速排序

算法基本原理:

快速排序(Quicksort)是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

算法实现:

//快速排序开始,使用递归方法,取其中一个数(任意,基本上都是以第一个为准),先从后面比较,如果这个数比后面的大交换之,如果不大继续比较直到大为止,如果大,则交换之,再到前面比较,如果前面的比这个数小交换之再和后面的比较,第一趟下来比它小的就在前面了,比它大的就在后面喽,然后再把该数组分成两部分使用递归,直到最后排序完成

void Sort(int array[], int low, int hight)
{
    int i,j,t,m;
    if(low<hight)
    {
        i = low;
        j = hight;
        t = array[low];
        while(i<j)
        {
            while(i<j && array[j]>t)//开始和后面的比较,如果后面的比他大继续,如果后面的比它小交换之
            {
                j--;
            }
            if(i<j)//在没有越界(i是从前面开始,j是从后面开始)的情况下进行交换
            {
                m=array[i];
                array[i]=array[j];
                array[j]=m;
                i++;//让前面的向后移动一个继续比较
            }
            while(i<j && array[i]<=t)//和前面的比较,如果前面的小于等于该关键数据继续,如果大于交换之
            {
                i++;
            }
            if(i<j)
            {
                m=array[j];
                array[j]=array[i];
                array[i]=m;
                j--;
            }
        }
        array[i]=t;//第一次比较结束,把i放到中间的位置,也即在i前面都比i小,在i后面都比i大
        Sort(array, low, i-1);//前面部分实现递归
        Sort(array, i+1, hight);//后面部分实现递归
    }
}

void quickSort()
{
    int s=0;
    int array[] = {10,22,3,21,45,67,2,11,110,453};
    int length = sizeof(array)/sizeof(array[0]);
    Sort(array,s,length-1);
    for(s=0;s<length;s++)
    {
        printf("%d \n",array[s]);
    }
}

选择排序

算法基本原理:
一次选定数组中的每一个数,记下当前位置并假设它是从当前位置开始后面数中的最小数min=i,从这个数的下一个数开始扫描直到最后一个数,并记录下最小数的位置min,扫描结束后如果min不等于i,说明假设错误,否则交换min与i位置上数。

算法实现:

//选择排序,如果第一个数字小于后面的则向后移动,依次类推该排序是不稳定的,时间复杂度是N平方

void choseSort()
{
    int array[10] = {112,4,2,3,5,33,6,7,8,9};//定义一个数组
    int length = sizeof(array)/sizeof(array[0]);//得到数组的长度
    int k=0, s=0, i=0, j=0;//k保存临时结果,s,i,j为循环变量
    //选择排序开始
    for(i=0;i<length;i++)
    {
        for(j=i+1;j<length;j++)
        {
            if(array[i]>array[j])
            {
                k=array[i];
                array[i]=array[j];
                array[j]=k;
            }
        }
    }
    //选择排序结束,输出显示排序的结果
    for(s=0; s<length; s++)
    {
        printf("%d \n",array[s]);
    }
}

归并排序

算法基本原理:

归并排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

算法实现:

void Merge(int A[],int low,int mid,int high)      
 {      
     int i,j,k;    
     int *P = new int[mid-low+1],*Q = new int[high-mid];      
     
     for (i =0;i  < mid - low +1;++i)   P[i] = A[i+low];
          
     for (i = 0; i  < high - mid;++i)   Q[i] = A[mid+1+i];      
      
     i = j = 0,k = low;      
     while ((i  <= mid-low) && (j  <= high-mid-1))      
     {      
      
         if (P[i]  <= Q[j])   A[k++] = P[i++];      
         else  A[k++]= Q[j++];      
     }      
      
     if (i > mid - low)   { for (;j  <= high-mid-1;++j)   A[k++] = Q[j]; }      
     else     
     {   for (; i <= mid - low;++i)   A[k++] = P[i];  }      
      
     delete [] P;      
     delete [] Q;      
 }      
      
 void mergeSort(int A[],int left,int right)      
 {      
     if (left  < right)      
     {      
         int i = (left + right) / 2;      
         MergeSort(A,left,i);      
         MergeSort(A,i+1,right);      
         Merge(A,left,i,right);      
     }      
 }      
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,101评论 0 52
  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,706评论 0 15
  • 概述排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的...
    Luc_阅读 2,213评论 0 35
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,177评论 0 2
  • 我的幸运是听到你的所有、 不含一滴晨露、不含色彩、 没有那五千瓦日光灯下的亮色、 没有那高楼竖立的危仪 直到雨踏过...
    青山撩丝寄风华阅读 162评论 0 1