Linux C 算法——排序

 排序(Sort)是将无序的记录序列(或称文件)调整成有序的序列。

     为了方便讨论,在此首先要对排序下一个确切的定义:

假设含有n个记录的序列为

             { R1、R2、,。。。Rn }

其相应的关键字序列为

             {K1、K2,。。。。Kn}

需确定1,2,。。。,n的一种排列 p1,p2,。。。pn,使其相应的关键字满足如下的非递减(或非递增)关系

            Kp1 <= Kp2 <=........<= Kpn

即使这个序列称为一个按关键字有序的序列

           {Rp1,Rp2,...., Rpn}

这样的操作称为排序

 

排序分类:

1、稳定排序和非稳定排序

    假设关键字 Ki = Kj (1 <= i <= n , 1<= j <= n , i != j ),且在排序前的序列中 Ri 领先于 Rj (即 i < j)。若在排序后的序列中,Ri 仍领先于 Rj ,则称所用的排序方法是稳定的;反之,若可能使排序后的序列中Rj 领先于 Ri ,则称所用的排序方法是不稳定的的。

2、内排序和外排序

    内排序指的是待排序记录存放在计算机随机存储器中进行的排序过程;外排序是指待排序记录的数量很大,以致内存依次不能容纳全部记录,在排序过程中尚需对外存进行访问的排序过程。

总之,在排序的过程中需进行下列两种基本操作:1) 比较两个关键字的大小 ;2)将记录从一个位置移动到另一个位置;

下面讨论内排序:

 

一、插入排序

1、直接插入排序

        直接排序是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表;

        设待排文件f = (R1  R2 ........... Rn)相应的 key 集合为k = {k1  k2  ........kn },其排序方法是:

        现将文件中的(R1)看成只含一个记录的有序子文件,然后从R2起,逐个将 R2 至 Rn按key插入到当前有序子文件中,最后得到一个有序的文件。插入的过程是一个key的比较过程,即每插入一个记录时,将其key 与当前有序字表中的key进行比较,找到待插入记录的位置后,将其插入即可。

[cpp] view plaincopy
  1. #define maxsize 1024 //文件最大长度  
  2. typedef int key_t;  //设key为整数  
  3. typedef struct //记录类型  
  4. {  
  5.     key_t key; //记录关键字  
  6.         .....  //记录其他域  
  7. }Retype;  
  8. typedef struct //文件或表的类型  
  9. {  
  10.     Retype R[maxsize + 1]; //文件存储空间  
  11.     int len; //当前记录数  
  12. }sqfile;  

若说明sqfile F ; 则(F.R[1],F.R[2],。。。F.R[F.len] )为待排文件,它是一种顺序结构;文件长度 n = F.len ;F.R[0] 为工作单元,起到“监视哨”的作用;记录的关键字ki 写作 F.R[i].key 。

算法描述:

[cpp] view plaincopy
  1. void Insort(sqfile F)  
  2. {  
  3.     int i,j;  
  4.     for(i = 2;i <= F;i++) //插入n - 1个记录  
  5.     {  
  6.         F.R[0] = F.R[i]; //带插入记录先存于监视哨  
  7.         j = i - 1;  
  8.         while(F.R[0].key < F.R[j].key) //key 比较  
  9.         {  
  10.             F.R[j + 1] = F[j]; //记录顺序后移  
  11.             j--;      
  12.         }  
  13.         F.R[j + 1] = F.R[0]; //原R[i]插入j + 1位置  
  14.     }  
  15. }  

排序的时间复杂度取耗时最高的量级,故直接插入排序的T(n) = O(n*n).

 

2、折半插入排序

     排序算法的T(n) = O(n*n) ,是内排序时耗最高的时间复杂度。随着文件记录数n的增大,效率降低较快,下面的一些插入排序的方法,都是围绕着改善算法的时间的复杂度而展开的。另外,直接插入排序是稳定排序。

     为了减少插入排序过程中key的比较次数,可采用折半插入排序。

排序方法:

     同直接插入排序,先将(R[1])看成一个子文件,然后依次插入R[2] .....R[n] 。但在插入R[i] 时,子表(R[1] 。。。R[i-1])已是有序的,查找R[i] 在子表中位置可按折半查找方法进行,从而降低key 的比较次数。

算法描述:

[cpp] view plaincopy
  1. void Binsort(sqfile F) //对文件F折半插入排序的算法  
  2. {  
  3.     int i,j,high,low,mid;  
  4.     for(i = 2;i <= F.len,i++) //插入n-1个记录  
  5.     {  
  6.         F.R[0] = F.R[i];//待插入记录存入监视哨  
  7.         low = 1;  
  8.         high = i - 1;  
  9.         while(low < high) //查找 R[i]的位置,即low = high 时;  
  10.         {  
  11.             mid = (low + high)/2;  
  12.             if(F.R[0].key >= F.R[mid].key)  
  13.                 low = mid + 1; //调整下界  
  14.             else  
  15.                 high =mid - 1;//调整上界  
  16.         }  
  17.           
  18.         for(j = i - 1;j >= low;j--)  
  19.             F.R[j + 1] = F.R[j]; //记录瞬移  
  20.           
  21.         F.R[low] = F.R[0]; //原R[i]插入low位置  
  22.     }  
  23. }  


二、交换排序
1、起泡排序

     设待排文件  f = (R1 R2  。。。Rn),相应key集合k = {k1 ,k2, ......kn}。

排序方法

从k1起,两两key比较,逆序时交换,即:

 k1~k2,若 k1 > k2 ,则R1 与 R2 交换;

.....

k n-1 ~ kn,若kn-1 > kn ,则Rn-1 与 Rn 交换。

 经过一趟比较之后,最大key的记录沉底,类似水泡。接着对前n-1个记录重复上述过程,直到排序完毕。

起泡排序的市价你复杂度 T(n) = O(n*n) 。

算法描述:

[cpp] view plaincopy
  1. void Bubsort(sqfile F)  
  2. {  
  3.     int i,flag; //flag 作为记录交换的标志  
  4.     Retype temp;  
  5.     for(i = F.len;i > 2;i--) //最多n - 1次排序  
  6.     {  
  7.         flag = 0;  
  8.         for(j = 1; j <= i - 1;j++) //一趟起泡排序  
  9.         {  
  10.             if(F.R[j].key > F.R[j + 1].key) //两两比较  
  11.             {  
  12.                 temp = F.R[j]; //交换  
  13.                 F.R[j] = F.R[j + 1];  
  14.                 F.R[j + 1] = temp;  
  15.                 flag = 1;     
  16.             }  
  17.             flag = 1;  
  18.         }  
  19.         if(flag == 0) //无记录交换时排序完毕  
  20.             break;  
  21.     }  
  22. }  

2、快速排序
      快速排序 
的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

     排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

算法描述:

1)一趟快排算法

[cpp] view plaincopy
  1. int Partition(sqfile *L,int low ,int high)  
  2. {  
  3.     key_t pivotkey; //基准key  
  4.     L->r[0] = L->r[low]; //存入基准记录  
  5.     pivotkey = L->r[low].key; //存入基准key  
  6.   
  7.     while(low < high)  
  8.     {  
  9.         while(low < high && L->r[high].key >= pivotkey) //逆序比较  
  10.             high--;    
  11.         if(low < high)  
  12.             L->r[low] = L->r[high]; //比 pivotkey小的key左移  
  13.   
  14.         while(low < high && L->r[low].key <= pivotkey) //正序比较  
  15.             low++;  
  16.         if(low < high)  
  17.             L->r[high] = L->r[low]; //比 pivotkey 大的右移  
  18.     }  
  19.     L->r[low] = L->r[0]; //基准记录存入第i位置  
  20.   
  21.     return low; //返回基准位置  
  22. }  

2)对文件L快速排序的算法(递归)

[cpp] view plaincopy
  1. void QSort(sqfile *L,int low ,int high)  
  2. {  
  3.     int  pivotloc;  
  4.     int i;  
  5.   
  6.     if(low < high)  
  7.     {  
  8.         pivotloc = Partition(L,low,high); //将L分成两部分  
  9.         QSort(L,low,pivotloc - 1); //对左部再排序  
  10.         QSort(L,pivotloc + 1,high); //对右部再排序  
  11.     }  
  12. }  

下面是个测试程序:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #define maxsize 1024  
  3.   
  4. typedef int key_t;  
  5.   
  6. typedef struct  
  7. {  
  8.     key_t key;  
  9. }Retype;  
  10.   
  11. typedef struct  
  12. {  
  13.     Retype r[maxsize + 1];  
  14.     int len;  
  15. }sqlist;  
  16.   
  17. int Partition(sqlist *L,int low ,int high)  
  18. {  
  19.     key_t pivotkey;  
  20.     L->r[0] = L->r[low];  
  21.     pivotkey = L->r[low].key;  
  22.   
  23.     while(low < high)  
  24.     {  
  25.         while(low < high && L->r[high].key >= pivotkey)  
  26.             high--;  
  27.         if(low < high)  
  28.             L->r[low] = L->r[high];  
  29.   
  30.         while(low < high && L->r[low].key <= pivotkey)  
  31.             low++;  
  32.         if(low < high)  
  33.             L->r[high] = L->r[low];  
  34.     }  
  35.     L->r[low] = L->r[0];  
  36.   
  37.     return low;  
  38. }  
  39.   
  40. void QSort(sqlist *L,int low ,int high)  
  41. {  
  42.     int  pivotloc;  
  43.     int i;  
  44.   
  45.     if(low < high)  
  46.     {  
  47.         pivotloc = Partition(L,low,high);  
  48.         QSort(L,low,pivotloc - 1);  
  49.         QSort(L,pivotloc + 1,high);  
  50.     }  
  51. }  
  52.   
  53. int main()  
  54. {  
  55.     int i;  
  56.     sqlist L;  
  57.     L.len = 8;  
  58.     key_t a[8] = {50,36,66,76,36,12,25,95};  
  59.   
  60.     for(i = 1; i < 9; i++)  
  61.     {  
  62.         L.r[i].key = a[i - 1];  
  63.     }  
  64.   
  65.     printf("Begin sorting!\n");  
  66.   
  67.     QSort(&L,1,8);  
  68.     for(i = 1; i < 9; i++)  
  69.     {  
  70.         printf("%d ",L.r[i].key);  
  71.     }  
  72.     printf("\n");  
  73.   
  74.     return 0;  
  75. }  

执行结果如下:

[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/sort$ ./quicksort   
  2. Begin sorting!  
  3. 12 25 36 36 50 66 76 95   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402388.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTP错误代码

服务器错误代码大全 400 - 错误的请求。 401 - 访问被拒绝。IIS 定义了许多不同的 401 错误&#xff0c;它们指明更为具体的错误原因。这些具体的错误代码在浏览器中显示&#xff0c;但不在 IIS 日志中显示&#xff1a; 401.1 - 登录失败。 401.2 - 服务器配置导致登录失败。 4…

UIKit封装的系统动画

简介 在UIKit中&#xff0c;对UIView封装了很多类方法来进行简单的动画实现&#xff0c;在动画过程中&#xff0c;通过对属性值的修改来完成一系列的效果。 在IOS4以前&#xff0c;主要通过 beginAnimation setAnimationDuration:设置动画时长 setAnimationDelay:设置延迟时…

MS SQL Server2008大数、小数转varchar

HTJE在表中的字段类型为float(53) 试了下str, cast和convert&#xff0c;发现对于小数或大数&#xff0c;多少都存在一些问题&#xff0c;最后经过尝试终于找到一种满意的答案&#xff1a; select cast(HTJE as decimal(20,2)) from T_HTGL where ID 1002993 对于金额部分&…

oracle那些基本知识

Oracle创建表空间、创建用户以及授权 、查看权限 rownum 分页查询 它是oracle系统顺序分配为从查询返回的行的编号&#xff0c;返回的第一行分配的是1&#xff0c;第二行是2&#xff0c;依此类推&#xff0c;这个伪字段可以用于限制查询返回的总行数&#xff0c;而且rownum不能…

JSON.parse 解析json字符串时,遇换行符报错

Json字符串转换成Json对象时候&#xff0c;有两种方式&#xff1a; 假设d是json字符串&#xff1a; 1&#xff0c;eval(( d ))。 2&#xff0c;JSON.parse(d)&#xff1b; 但是以上方式有隐患&#xff0c;如果Json字符串有换行的话&#xff0c;这样转换就会报错。 假如有…

jqueryui dialog asp.net服务端控件失效问题解决

最近使用jQuery Dialog做添加功能&#xff0c;发现服务端控件全部失效。 查资料是因为Dialog层被appendto 到了 body里&#xff0c;不在form里。 但网上给的解决方案我都不满意&#xff0c;觉得jQueryUI不会忽略这个问题&#xff0c;就查了API。 发现这个属性appendTo $( "…

用ASP生成RSS

<% Response.Clear Response.CharSet"gb2312" 数据集 Response.ContentType"text/xml" 数据流格式定义 Response.Write "<?xml version""1.0"" encoding""gb2312""?>"&vbNewLinesRssHea…

PHP中全局变量的使用global和$GLOBALS[]

From: http://blog.csdn.net/happyqyt/article/details/7219889 用PHP开发项目&#xff0c;不可避免的会使用到全局变量&#xff0c;比如一些网站的配置信息&#xff0c;全站通用&#xff0c;那就可以在一个地方设置&#xff0c;然后多个地方调用。 把变量定义为全局变量可以有…

PHP中常见错误

1、Notice: Undefined variable: 变量名 in 注&#xff1a;使用了一个没有被定义的变量 2、Parse error: syntax error, unexpected T_ELSE in If () { }Else if () { } Echo $test; Else { } 注&#xff1a;是 if else if else 句式错误 3、Parse error: syntax er…

文件I/O和标准I/O的区别

一、先来了解下什么是文件I/O和标准I/O&#xff1a; 文件I/O&#xff1a;文件I/O称之为不带缓存的IO&#xff08;unbuffered I/O)。不带缓存指的是每个read&#xff0c;write都调用内核中的一个系统调用。也就是一般所说的低级I/O——操作系统提供的基本IO服务&#xff0c;与os…

程序集、应用程序配置及App.config和YourSoft.exe.config .

转自&#xff1a;http://www.cnblogs.com/luminji/archive/2010/10/21/1857339.html 什么是程序集 程序集标识属性 强名称的程序集 强名称工作原理配置文件使用 DEVPATH 查找程序集指定要使用的运行库版本Appconfig和YourSoftexeconfig本章概要&#xff1a; 1&#xff1a;什么是…

用GDB调试程序(一)

GDB概述 ———— GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许&#xff0c;各位比较喜欢那种图形界面方式的&#xff0c;像VC、BCB等IDE的调试&#xff0c;但如果你是在UNIX平台下做软件&#xff0c;你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大…

程序员必须注意的十大编程禁忌

一、不提升非技术技能我们认为非技术技能是项目成功的主要因素。这些非技术技能也可以称之为“软技能”&#xff0c;总体上来说&#xff0c;它已经被公司证明为能够驾驭企业和客户之间的长期商业关系&#xff0c;因此也能决定公司的成长发展路径。一些关键的软技能指标包括&…

Linux 系统应用编程——出错处理(errno)

1. errno变量 文件 <errno.h> 中定义了符号 errno 以及可以赋予它的各种常量,这些常量都是以字符 E 开头。例如,若 errno 等于常量 EACCES,表示产生了权限问题(例如,没有打开所要求文件的足够权限)。 当 UNIX 函数出错时,常常返回一个负值,而且将整型变量 errno 设置…

有关MSHTML

http://msdn.microsoft.com/zh-HK/library/aa741322有关MHTML的接口参考文档转载于:https://blog.51cto.com/amcto111/1284453

[Android]在Dagger 2中使用RxJava来进行异步注入(翻译)

以下内容为原创&#xff0c;欢迎转载&#xff0c;转载请注明 来自天天博客&#xff1a;http://www.cnblogs.com/tiantianbyconan/p/6236646.html 在Dagger 2中使用RxJava来进行异步注入 原文&#xff1a;http://frogermcs.github.io/async-injection-in-dagger-2-with-rxjava 几…

关于Go语言在服务端做Restful接口和socket通信

请到我的个人博客看golang rest相关文章 http://xiaorui.cc关于Go语言在服务端做Restful接口和socket通信已经转到: http://xiaorui.cc/2014/10/25/%E5%85%B3%E4%BA%8Ego%E8%AF%AD%E8%A8%80%E5%9C%A8%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%81%9Arestful%E6%8E%A5%E5%8F%A3%E5%92%8C…

Linux 系统应用编程——文件I/O

Linux操作系统是基于文件概念的。文件是以字符序列构成的信息载体。根据这一点&#xff0c;可以把I/O设备当做文件来处理&#xff0c;因此&#xff0c;在磁盘上的普通文件进行交互所用的统一系统调用可以直接用于I/O设备。这样大大简化了系统对于不同设备的处理&#xff0c;提高…

Socket模型详解

Socket模型详解 Winsock 的I/O操作&#xff1a;1、两种I/O模式 阻塞模式&#xff1a;执行I/O操作完成前会一直进行等待&#xff0c;不会将控制权交给程序。套接字默认为阻塞模式。可以通过多线程技术进行处理。 非阻塞模式&#xff1a;执行I/O操作时&#xff0c;Winsock函数会…