关于排序

原创 2013年07月12日 20:46:34

以前一般情况下的排序我都用冒泡排序,比较容易记,也就两个for循环就可以了,时间复杂度是O(n^2),n比较小,不用考虑是否超时,但当n>=100000的时候就会超时,所以再做排序的时候我们就要考虑时间复杂度的问题,今天学到了一个新的排序方法,是一个sort函数,可以直接进行排序,时间复杂度也只有O(n*log2(n))。

包含头文件#include<algorithm>

这个函数需要2个或3个参数,第一个参数是要排序的区间首地址,第二个区间尾地址+1,对于一个数组int a[100].排序sort(a,a+100)就行了,默认排序为升序。

1.普通排序,升序

01 #include <iostream>
02 #include <algorithm>
03 using namespace std;
04 int main()
05 {
06  int a[10]={7,3,4,6,5,1,2,9,8,0};
07  sort(a,a+10);
08  for(int i=0;i<10;i++)
09  cout<<a[i]<<" ";
10  return 0;
11 }
12 OUTPUT:0 1 2 3 4 5 6 7 8 9

普通排序,降序

01 #include <iostream>
02 #include <algorithm>
03 using namespace std;
04 bool cmp(int a,int b)
05 {
06  return a>b;
07 }
08 int main()
09 {
10  int a[10]={7,3,4,6,5,1,2,9,8,0};
11  sort(a,a+10,cmp);
12  for(int i=0;i<10;i++)
13  cout<<a[i]<<" ";
14  return 0;
15 }
16 OUTPUT:9 8 7 6 5 4 3 2 1 0


2.结构体排序,a升,b降,c降

01 #include <iostream>
02 #include <algorithm>
03 using namespace std;
04 struct data
05 {
06  int a;
07  int b;
08  int c;
09 };
10 bool cmp(data x,data y)
11 {
12  if(x.a!=y.a) return x.a<x.y;
13  if(x.b!=y.b) return x.b>y.b;
14  if(x.c!=y.c) return x.c>y.c;
15 }
16 int main()
17 {
18  .....
19  sort(array,array+n,cmp);
20  return 0;
21 }



排序的数据类型不局限于整数,只要是定义了小于运算的类型都可以,比如字符串类 string 。

如果是没有定义小于运算的数据类型,或者想改变排序的顺序,就要用到第三参数——比较函数。比较函数是一个自己定义的函数,返回值是 bool 型,它规定了什么样的关系才是“小于”。想把刚才的整数数组按降序排列,可以先定义一个比较函数 cmp 

bool cmp(int a,int b) 

return a>b; 

排序的时候就写 sort(a,a+100,cmp); 

假设自己定义了一个结构体 node 

struct node

int a; 

int b; 

double c; 

有一个 node 类型的数组 node arr[100] ,想对它进行排序:先按 a 值升序排列,如果 a 值相同,再按 b 值降序排列,如果 b 还相同,就按 c 降序排列。就可以写这样一个比较函数:

以下是代码片段:

bool cmp(node x,node y) 

if(x.a!=y.a) return x.a 

if(x.b!=y.b) return x.b>y.b; 

return return x.c>y.c; 

排序时写 sort(arr,a+100,cmp); 




七种 qsort 排序方法 

< 本文中排序都是采用的从小到大排序 > 

一、对 int 类型数组排序 

int num[100]; 

Sample: 

int cmp ( const void *a , const void *b ) 

return *(int *)a - *(int *)b; 

qsort(num,100,sizeof(num[0]),cmp); 

二、对 char 类型数组排序(同 int 类型) 

char word[100]; 

Sample: 

int cmp( const void *a , const void *b ) 

return *(char *)a - *(char *)b; 

qsort(word,100,sizeof(word[0]),cmp); 

三、对 double 类型数组排序(特别要注意) 

double in[100]; 

int cmp( const void *a , const void *b ) 

return *(double *)a > *(double *)b ? 1 : -1; 

qsort(in,100,sizeof(in[0]),cmp) ; 

四、对结构体一级排序 

struct In 

double data; 

int other; 

}s[100] 

// 按照 data 的值从小到大将结构体排序 , 关于结构体内的排序关键数据 data 的类型可以很多种,参考上面的例子写 

int cmp( const void *a ,const void *B) 

return (*(In *)a)->data > (*(In *)B)->data ? 1 : -1; 

qsort(s,100,sizeof(s[0]),cmp); 

五、对结构体二级排序 

struct In 

int x; 

int y; 

}s[100]; 

// 按照 x 从小到大排序,当 x 相等时按照 y 从大到小排序 

int cmp( const void *a , const void *b ) 

struct In *c = (In *)a; 

struct In *d = (In *)b; 

if(c->x != d->x) return c->x - d->x; 

else return d->y - c->y; 

qsort(s,100,sizeof(s[0]),cmp); 

六、对字符串进行排序 

struct In 

int data; 

char str[100]; 

}s[100]; 

// 按照结构体中字符串 str 的字典顺序排序 

int cmp ( const void *a , const void *b ) 

return strcmp( (*(In *)a)->str , (*(In *)B)->str ); 

qsort(s,100,sizeof(s[0]),cmp); 

七、计算几何中求凸包的 cmp 

int cmp(const void *a,const void *B) // 重点 cmp 函数,把除了 1 点外的所有点,旋转角度排序 

struct point *c=(point *)a; 

struct point *d=(point *)b; 

if( calc(*c,*d,p[1]) < 0) return 1; 

else if( !calc(*c,*d,p[1]) && dis(c->x,c->y,p[1].x,p[1].y) < dis(d->x,d->y,p[1].x,p[1].y)) // 如果在一条直线上,则把远的放在前面 

return 1; 

else return -1; 

}



其他一些排序

堆排序

1、 堆排序定义
 n个关键字序列KlK2Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质)
 (1) ki≤K2iki≤K2i+1 或(2)Ki≥K2iki≥K2i+1(1≤i≤ )

 若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
【例】关键字序列(101556253070)(705630251510)分别满足堆性质(1)(2),故它们均是堆,其对应的完全二叉树分别如小根堆示例和大根堆示例所示。



2、大根堆和小根堆
 根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆。
 根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆。
注意:
堆中任一子树亦是堆。
  以上讨论的堆实际上是二叉堆(Binary Heap),类似地可定义k叉堆。

3、堆排序特点
 堆排序(HeapSort)是一树形选择排序。
 堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系【参见二叉树的顺序存储结构】,在当前无序区中选择关键字最大(或最小)的记录。

4、堆排序与直接插入排序的区别
 直接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。
 堆排序可通过树形结构保存部分比较结果,可减少比较次数。

5、堆排序
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

1)用大根堆排序的基本思想
 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
 由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。

2)大根堆排序算法的基本操作:
 初始化操作:将R[1..n]构造为初始堆;
 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)
注意:
只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。
用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。堆排序和直接选择排序相反:在任何时刻,堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止。

3)堆排序的算法:
void HeapSort(SeqIAst R)
{ //R[1..n]进行堆排序,不妨用R[0]做暂存单元
int i
BuildHeap(R); //R[1-n]建成初始堆
for(i=n;i>1i--){ //对当前无序区R[1..i]进行堆排序,共做n-1趟。
R[0]=R[1]R[1]=R[i];R[i]=R[0]; //将堆顶和堆中最后一个记录交换
  Heapify(R1i-1); //R[1..i-1]重新调整为堆,仅有R[1]可能违反堆性质
} //endfor
} //HeapSort

4) BuildHeapHeapify函数的实现
 因为构造初始堆必须使用到调整堆的操作,先讨论Heapify的实现。
 Heapify函数思想方法
 每趟排序开始前R[l..i]是以R[1]为根的堆,在R[1]R[i]交换后,新的无序区R[1..i-1]中只有R[1]的值发生了变化,故除R[1]可能违反堆性质外,其余任何结点为根的子树均是堆。因此,当被调整区间是R[low..high]时,只须调整以R[low]为根的树即可。
"筛选法"调整堆
  R[low]的左、右子树(若存在)均已是堆,这两棵子树的根R[2low]R[2low+1]分别是各自子树中关键字最大的结点。若R[low].key不小于这两个孩子结点的关键字,则R[low]未违反堆性质,以R[low]为根的树已是堆,无须调整;否则必须将R[low]和它的两个孩子结点中关键字较大者进行交换,即R[low]R[large](R[large].key=max(R[2low].keyR[2low+1].key))交换。交换后又可能使结点R[large]违反堆性质,同样由于该结点的两棵子树(若存在)仍然是堆,故可重复上述的调整过程,对以R[large]为根的树进行调整。此过程直至当前被调整的结点已满足堆性质,或者该结点已是叶子为止。上述过程就象过筛子一样,把较小的关键字逐层筛下去,而将较大的关键字逐层选上来。因此,有人将此方法称为"筛选法"
  具体的算法【参见教材】

BuildHeap的实现
  要将初始文件R[l..n]调整为一个大根堆,就必须将它所对应的完全二叉树中以每一结点为根的子树都调整为堆。
  显然只有一个结点的树是堆,而在完全二叉树中,所有序号 的结点都是叶子,因此以这些结点为根的子树均已是堆。这样,我们只需依次将以序号为 , -11的结点作为根的子树都调整为堆即可。
  具体算法【参见教材】。

5、大根堆排序实例
 对于关键字序列(4213249123160588),在建堆过程中完全二叉树及其存储结构的变化情况参见【动画演示】。

6、 算法分析
 堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用Heapify实现的。
  堆排序的最坏时间复杂度为O(nlgn)。堆排序的平均性能较接近于最坏性能。
 由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。
 堆排序是就地排序,辅助空间为O(1)
 它是不稳定的排序方法。


归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法Divide and Conquer)的一个非常典型的应用。值得注意的是归并排序是一种稳定的排序方法。

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序,称为2-路归并。

归并操作

归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。

如 设有数列{62021003013881}

初始状态: [6] [202] [100] [301] [38] [8] [1]  比较次数

i=1  [6 202 ] [ 100 301] [ 8 38] [ 1 ]  3

i=2  [ 6 100 202 301 ] [ 1 8 38 ]  4

i=3  [ 1 6 8 38 100 202 301 ]  4

总计: 11

算法描述

归并操作的工作原理如下:

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置

第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

重复步骤3直到某一指针达到序列尾

将另一序列剩下的所有元素直接复制到合并序列尾

比较

归并排序是稳定的排序.即相等的元素的顺序不会改变.如输入记录 1(1) 3(2) 2(3) 2(4) 5(5) (括号中是记录的关键字)时输出的 1(1) 2(3) 2(4) 3(2) 5(5) 中的和 是按输入的顺序.这对要排序数据包含多个信息而要按其中的某一个信息排序,要求其它信息尽量按输入的顺序排列时很重要.这也是它比快速排序优势的地方.



Hive优化----排序

hive 中的排序优化 在hive中进行字段排序统计过程中,使用ORDER BY是全局排序,hive只能通过一个reduce进行排序.效率很低,采用hive提供的distribute by +s...
  • csliuruidongdn
  • csliuruidongdn
  • 2014年01月08日 16:10
  • 1151

《谁排第一?关于评价和排序的科学》中文版的纠错

最近,我读了一本好书——《谁排第一?关于评价和排序的科学》。这本书的作者是Amy N. Langville和Carl D.Meyer,译者是郭思羽。这本书的姊妹篇是《网页排名PR值及其他——搜索引擎排...
  • u011300443
  • u011300443
  • 2015年07月10日 23:47
  • 987

Hdu1157 完全的水题,排序找中值的

ACM博客_kuangbin 新博客kuangbin.org 人一我百,人十我万!追逐青春的梦想,怀着自信的心,永不放弃! by kuangbin 新博客 kuangbin.org ACM HDU...
  • qq_33913037
  • qq_33913037
  • 2017年05月30日 14:03
  • 110

查找与排序小结

//顺序查找 //主要是为了说明引入"哨兵"的作用 typedef struct { //查找表的数据结构 ElemType *elem; //元素存储空间基址,建表时按实际长度分配,0号单元留...
  • o1101574955
  • o1101574955
  • 2015年03月14日 11:35
  • 803

UITable排序问题

在开启了UITable的Sort之后回发现,默认是对子项的name属性进行升序的 但问题出现于我们经常用数字(例如循环中的i)命名这些子项,如1、2、3...8、9、10、11 一经排序就...
  • u014779452
  • u014779452
  • 2015年09月07日 12:47
  • 145

List自定义排序 (例子省份排序)

//待排序集合 List list=new ArrayList(); list.add("辽宁"); list.add("浙江"); list.add("河北"); list.add(...
  • qq_21492635
  • qq_21492635
  • 2017年08月21日 14:30
  • 95

一个简单的排序面试题

* 一个小面试题: * There is an array 2,10,11,4,21,5,7,6,19,15,please sort them with below order * The m...
  • z507263441
  • z507263441
  • 2015年08月26日 11:29
  • 553

排序问题——内部排序

1、排序的基本概念:假设含有n个记录的序列为{r1,r2,.....,rn},其相应的关键字分别为{k1,k2,..,..kn},需确定1,2,….,n的一种排列p1,p2,....,pn,使其相应的...
  • Din_Lei
  • Din_Lei
  • 2018年01月16日 18:48
  • 14

C++ 实现几种排序

写几个常用的排序: 1)冒泡排序 2)选择排序 3)插入排序 4)归并排序 5)快速排序 6)希尔排序 具体实现: 1. 冒泡排序 //冒泡排序 //i: sta...
  • anialy
  • anialy
  • 2012年05月29日 20:30
  • 8600

java ArrayList自动排序算法的实现

前几天写的那个是错误的,在这里将正确的更新。。。 通过实现ComParator接口,并且对Compare函数进行重写,自定义排序规则实现对ArrayList中对象的排序。。 Student类定义:...
  • fusugongzi
  • fusugongzi
  • 2016年05月22日 09:28
  • 1120
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于排序
举报原因:
原因补充:

(最多只允许输入30个字)