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,一经查实,立即删除!

相关文章

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

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

文件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;什么是…

[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…

UVa 11136 - Hoax or what

题目大意&#xff1a;超市进行促销活动&#xff0c;顾客可以把账单放到一个箱子里&#xff0c;每天超市会从箱子中抽出最高消费者和最低消费者&#xff0c;最高消费者可以得到&#xff08;最高消费-最低消费&#xff09;的金钱。询问超市在n天的促销活动结束后应支付多少钱。 找…

Winfrom实现圆角设计

主要代码 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Paint(object sender, PaintEventArgs e) { Type(this, 25, 0.1); } private void…

Linux 系统应用编程——进程基础

一、Linux下多任务机制的介绍 Linux有一特性是多任务&#xff0c;多任务处理是指用户可以在同一时间内运行多个应用程序&#xff0c;每个正在执行的应用程序被称为一个任务。 多任务操作系统使用某种调度(shedule)策略&#xff08;由内核来执行&#xff09;支持多个任务并发执行…

【Python文件处理】递归批处理文件夹子目录内所有txt数据

因为有个需求&#xff0c;需要处理文件夹内所有txt文件&#xff0c;将txt里面的数据筛选&#xff0c;重新存储。 虽然手工可以做&#xff0c;但想到了python一直主张的是自动化测试&#xff0c;就想试着写一个自动化处理数据的程序。 一.分析数据格式 需要处理的数据是txt格式存…

Windows Azure 之服务总线中继服务

Windows Azure的服务总线允许在Web服务内部与外部之间做成一个公共的连接点&#xff0c;在无需更改企业防火墙或者其他安全配置的情况下连接内部和外部的服务 而使用Azure云服务的时候由于缩放的原因通过IP来制定连接也是不科学的&#xff0c;而中继服务则可以充当很好的公共连…

【qt】QT 的信号与槽机制

QT 是一个跨平台的 C GUI 应用构架&#xff0c;它提供了丰富的窗口部件集&#xff0c;具有面向对象、易于扩展、真正的组件编程等特点&#xff0c;更为引人注目的是目前 Linux 上最为流行的 KDE 桌面环境就是建立在 QT 库的基础之上。 QT 支持下列平台&#xff1a;MS/WINDOWS-9…

Linux 系统应用编程——进程间通信(上)

现在再Linux应用较多的进程间通信方式主要有以下几种&#xff1a; 1&#xff09;无名管道&#xff08;pipe&#xff09;及有名管道&#xff08;fifo&#xff09;&#xff1a;无名管道可用于具有亲缘关系进程间的通信&#xff1b;有名管道除具有管道相似的功能外&#xff0c;它还…

通过JDBK操作数据库

一、配置程序——让我们程序能找到数据库的驱动jar包1.把.jar文件复制到项目中去,整合的时候方便。2.在eclipse项目右击“构建路径”--“配置构建路径”--“库”--“添加外部jar”--找到数据库的驱动jar包--点击确定。会在左侧包资源管理器中出现“引用的库”&#xff0c;在里面…

Linux 系统应用编程——网络编程(常用命令解析)

1、telnet Telnet协议是TCP/IP协议族中的一员&#xff0c;是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序&#xff0c;用它连接到服务器。终端使用者可以在telnet程序中输入命令&#…

灾难 BZOJ 2815

灾难 【样例输入】 5 0 1 0 1 0 2 3 0 2 0 【样例输出】 4 1 0 0 0 题解&#xff1a; 先跑出拓扑序 我们按拓扑序建立一棵“灭绝树” 灭绝树含义是当一个点灭绝时&#xff0c;它的子树将会全部灭绝 所以答案就是点在灭绝树中的子树大小 一个点如果灭绝&#xff0c;那么需要所有…

centos关于”running yum-complete-transaction first...

2019独角兽企业重金招聘Python工程师标准>>> 今天在用yum安装软件出错几次户&#xff0c;总是有提示信息&#xff1a; There are unfinished transactions remaining. You might consider running yum-complete-transaction first to finish them. The program yum…

js身份证号、电话脱敏处理(用*替换中间数据)

数字类型 certificatecodecopy certificatecode.replace(/^(.{6})(?:\d)(.{4})$/, "\$1****\$2"); 所有类型 enginenocopy engineno.replace(/^(.{2})(?:\w)(.{1})$/, "\$1****\$2"); enginenocopy engineno.replace(/^(.{4})(?:\w)(.{4})$/, &…

Linux 系统应用编程——网络编程(I/O模型)

Unix下可用的5种I/O模型&#xff1a;阻塞I/O非阻塞I/OI/O复用(select和poll)信号驱动I/O(SIGIO)异步I/O(POSIX的aio_系列函数)一个输入操作通常包括两个不同的阶段&#xff1a;1&#xff09;等待数据准备好&#xff1b;2&#xff09;从内核向进程复制数据&#xff1b;对于一个套…

Linux 系统应用编程——网络编程(TCP/IP 数据包格式解析)

图中括号中的数字代表的是当前域所占的空间大小&#xff0c;单位是bit位。 黄色的是数据链路层的头部&#xff0c;一共14字节 绿色的部分是IP头部&#xff0c;一般是20字节 紫色部分是TCP头部&#xff0c;一般是20字节 最内部的是数据包内容 黄色部分&#xff1a;链路层 目的MA…