我博客里收藏的,粘给你 排序有哪几种好方法( 1 )from csdn2009-12-03 19:26 排序小结 排序算法是一种基本并且常用的算法。由于实际工作中处理的数量巨大,所以排序算法 对算法本身的速度要求很高。 而一般我们所谓的算法的性能主要是指算法的复杂度,一般用O方法来表示。在后面我将 给出详细的说明。 对于排序的算法我想先做一点简单的介绍,也是给这篇文章理一个提纲。 我将按照算法的复杂度,从简单到难来分析算法。 第一部分是简单排序算法,后面你将看到他们的共同点是算法复杂度为O(N*N)(因为没有 使用word,所以无法打出上标和下标)。 第二部分是高级排序算法,复杂度为O(Log2(N))。这里我们只介绍一种算法。另外还有几种 算法因为涉及树与堆的概念,所以这里不于讨论。 第三部分类似动脑筋。这里的两种算法并不是最好的(甚至有最慢的),但是算法本身比较 奇特,值得参考(编程的角度)。同时也可以让我们从另外的角度来认识这个问题。 第四部分是我送给大家的一个餐后的甜点——一个基于模板的通用快速排序。由于是模板函数 可以对任何数据类型排序(抱歉,里面使用了一些论坛专家的呢称)。 现在,让我们开始吧: 一、简单排序算法 由于程序比较简单,所以没有加什么注释。所有的程序都给出了完整的运行代码,并在我的VC环境 下运行通过。因为没有涉及MFC和WINDOWS的内容,所以在BORLAND C++的平台上应该也不会有什么 问题的。在代码的后面给出了运行过程示意,希望对理解有帮助。 1.冒泡法: 这是最原始,也是众所周知的最慢的算法了。他的名字的由来因为它的工作看来象是冒泡: #include iostream.h void BubbleSort(int* pData,int Count) { int iTemp; for(int i=1;iCount;i++) { for(int j=Count-1;j=i;j--) { if(pData[j]pData[j-1]) { iTemp = pData[j-1]; pData[j-1] = pData[j]; pData[j] = iTemp; } } } } void main() { int data[] = {10,9,8,7,6,5,4}; BubbleSort(data,7); for (int i=0;i7;i++) coutdata[i]" "; cout"\n"; } 倒序(最糟情况) 第一轮:10,9,8,7-10,9,7,8-10,7,9,8-7,10,9,8(交换3次) 第二轮:7,10,9,8-7,10,8,9-7,8,10,9(交换2次) 第一轮:7,8,10,9-7,8,9,10(交换1次) 循环次数:6次 交换次数:6次 其他: 第一轮:8,10,7,9-8,10,7,9-8,7,10,9-7,8,10,9(交换2次) 第二轮:7,8,10,9-7,8,10,9-7,8,10,9(交换0次) 第一轮:7,8,10,9-7,8,9,10(交换1次) 循环次数:6次 交换次数:3次 上面我们给出了程序段,现在我们分析它:这里,影响我们算法性能的主要部分是循环和交换, 显然,次数越多,性能就越差。从上面的程序我们可以看出循环的次数是固定的,为1+2+...+n-1。 写成公式就是1/2*(n-1)*n。 现在注意,我们给出O方法的定义: 若存在一常量K和起点n0,使当n=n0时,有f(n)=K*g(n),则f(n) = O(g(n))。(呵呵,不要说没 学好数学呀,对于编程数学是非常重要的!!!) 现在我们来看1/2*(n-1)*n,当K=1/2,n0=1,g(n)=n*n时,1/2*(n-1)*n=1/2*n*n=K*g(n)。所以f(n) =O(g(n))=O(n*n)。所以我们程序循环的复杂度为O(n*n)。 再看交换。从程序后面所跟的表可以看到,两种情况的循环相同,交换不同。其实交换本身同数据源的 有序程度有极大的关系,当数据处于倒序的情况时,交换次数同循环一样(每次循环判断都会交换), 复杂度为O(n*n)。当数据为正序,将不会有交换。复杂度为O(0)。乱序时处于中间状态。正是由于这样的 原因,我们通常都是通过循环次数来对比算法。 2.交换法: 交换法的程序最清晰简单,每次用当前的元素一一的同其后的元素比较并交换。 #include iostream.h void ExchangeSort(int* pData,int Count) { int iTemp; for(int i=0;iCount-1;i++) { for(int j=i+1;jCount;j++) { if(pData[j]pData[i]) { iTemp = pData[i]; pData[i] = pData[j]; pData[j] = iTemp; } } } } void main() { int data[] = {10,9,8,7,6,5,4}; ExchangeSort(data,7); for (int i=0;i7;i++) coutdata[i]" "; cout"\n"; } 倒序(最糟情况) 第一轮:10,9,8,7-9,10,8,7-8,10,9,7-7,10,9,8(交换3次) 第二轮:7,10,9,8-7,9,10,8-7,8,10,9(交换2次) 第一轮:7,8,10,9-7,8,9,10(交换1次) 循环次数:6次 交换次数:6次 其他: 第一轮:8,10,7,9-8,10,7,9-7,10,8,9-7,10,8,9(交换1次) 第二轮:7,10,8,9-7,8,10,9-7,8,10,9(交换1次) 第一轮:7,8,10,9-7,8,9,10(交换1次) 循环次数:6次 交换次数:3次 从运行的表格来看,交换几乎和冒泡一样糟。事实确实如此。循环次数和冒泡一样 也是1/2*(n-1)*n,所以算法的复杂度仍然是O(n*n)。由于我们无法给出所有的情况,所以 只能直接告诉大家他们在交换上面也是一样的糟糕(在某些情况下稍好,在某些情况下稍差)。 3.选择法: 现在我们终于可以看到一点希望:选择法,这种方法提高了一点性能(某些情况下) 这种方法类似我们人为的排序习惯:从数据中选择最小的同第一个值交换,在从省下的部分中 选择最小的与第二个交换,这样往复下去。 #include iostream.h void SelectSort(int* pData,int Count) { int iTemp; int iPos; for(int i=0;iCount-1;i++) { iTemp = pData[i]; iPos = i; for(int j=i+1;jCount;j++) { if(pData[j]iTemp) { iTemp = pData[j]; iPos = j; } } pData[iPos] = pData[i]; pData[i] = iTemp; } } void main() { int data[] = {10,9,8,7,6,5,4}; SelectSort(data,7); for (int i=0;i7;i++) coutdata[i]" "; cout"\n"; } 倒序(最糟情况) 第一轮:10,9,8,7-(iTemp=9)10,9,8,7-(iTemp=8)10,9,8,7-(iTemp=7)7,9,8,10(交换1次) 第二轮:7,9,8,10-7,9,8,10(iTemp=8)-(iTemp=8)7,8,9,10(交换1次) 第一轮:7,8,9,10-(iTemp=9)7,8,9,10(交换0次) 循环次数:6次 交换次数:2次 其他: 第一轮:8,10,7,9-(iTemp=8)8,10,7,9-(iTemp=7)8,10,7,9-(iTemp=7)7,10,8,9(交换1次) 第二轮:7,10,8,9-(iTemp=8)7,10,8,9-(iTemp=8)7,8,10,9(交换1次) 第一轮:7,8,10,9-(iTemp=9)7,8,9,10(交换1次) 循环次数:6次 交换次数:3次 遗憾的是算法需要的循环次数依然是1/2*(n-1)*n。所以算法复杂度为O(n*n)。 我们来看他的交换。由于每次外层循环只产生一次交换(只有一个最小值)。所以f(n)=n 所以我们有f(n)=O(n)。所以,在数据较乱的时候,可以减少一定的交换次数。 4.插入法: 插入法较为复杂,它的基本工作原理是抽出牌,在前面的牌中寻找相应的位置插入,然后继续下一张 #include iostream.h void InsertSort(int* pData,int Count) { int iTemp; int iPos; for(int i=1;iCount;i++) { iTemp = pData[i]; iPos = i-1; while((iPos=0) (iTemppData[iPos])) { pData[iPos+1] = pData[iPos]; iPos--; } pData[iPos+1] = iTemp; } } void main() { int data[] = {10,9,8,7,6,5,4}; InsertSort(data,7); for (int i=0;i7;i++) coutdata[i]" "; cout"\n"; } 倒序(最糟情况) 第一轮:10,9,8,7-9,10,8,7(交换1次)(循环1次) 第二轮:9,10,8,7-8,9,10,7(交换1次)(循环2次) 第一轮:8,9,10,7-7,8,9,10(交换1次)(循环3次) 循环次数:6次 交换次数:3次 其他: 第一轮:8,10,7,9-8,10,7,9(交换0次)(循环1次) 第二轮:8,10,7,9-7,8,10,9(交换1次)(循环2次) 第一轮:7,8,10,9-7,8,9,10(交换1次)(循环1次) 循环次数:4次 交换次数:2次 上面结尾的行为分析事实上造成了一种假象,让我们认为这种算法是简单算法中最好的,其实不是, 因为其循环次数虽然并不固定,我们仍可以使用O方法。从上面的结果可以看出,循环的次数f(n)= 1/2*n*(n-1)=1/2*n*n。所以其复杂度仍为O(n*n)(这里说明一下,其实如果不是为了展示这些简单 排序的不同,交换次数仍然可以这样推导)。现在看交换,从外观上看,交换次数是O(n)(推导类似 选择法),但我们每次 要进行与内层循环相同次数的‘=’操作。正常的一次交换我们需要三次‘=’ 而这里显然多了一些,所以我们浪费了时间。 最终,我个人认为,在简单排序算法中,选择法是最好的。
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:空间域名、雅安服务器托管、营销软件、网站建设、建水网站维护、网站推广。
错的地方很多。。改了下,
#includestdio.h
int sort(int num[5]);
void main()
{
int numm[5],i,a;
for (i=0;i5;i++)
scanf("%d",numm[i]);
sort(numm); //调用排序
for (i=0;i5;i++)
printf("%d ",numm[i]);
}
int sort(int num[5])
{
int m,n,t;
for (m=0;m4;m++)
for(n=m+1;n5;n++)//冒泡排序
{
if (num[m]num[n])
{
t=num[n];
num[n]=num[m];
num[m]=t;
}
}
return 1;
}
1、冒泡排序(最常用)
冒泡排序是最简单的排序方法:原理是:从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个。这个数就会从序列的最右边冒出来。(注意每一轮都是从a[0]开始比较的)
以从小到大排序为例,第一轮比较后,所有数中最大的那个数就会浮到最右边;第二轮比较后,所有数中第二大的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从小到大排序。
2、鸡尾酒排序
鸡尾酒排序又称双向冒泡排序、鸡尾酒搅拌排序、搅拌排序、涟漪排序、来回排序或快乐小时排序, 是冒泡排序的一种变形。该算法与冒泡排序的不同处在于排序时是以双向在序列中进行排序。
原理:数组中的数字本是无规律的排放,先找到最小的数字,把他放到第一位,然后找到最大的数字放到最后一位。然后再找到第二小的数字放到第二位,再找到第二大的数字放到倒数第二位。以此类推,直到完成排序。
3、选择排序
思路是设有10个元素a[1]-a[10],将a[1]与a[2]-a[10]比较,若a[1]比a[2]-a[10]都小,则不进行交换。若a[2]-a[10]中有一个以上比a[1]小,则将其中最大的一个与a[1]交换,此时a[1]就存放了10个数中最小的一个。同理,第二轮拿a[2]与a[3]-a[10]比较,a[2]存放a[2]-a[10]中最小的数,以此类推。
4、插入排序
插入排序是在一个已经有序的小序列的基础上,一次插入一个元素*
一般来说,插入排序都采用in-place在数组上实现。
具体算法描述如下:
⒈ 从第一个元素开始,该元素可以认为已经被排序
⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描
⒊ 如果该元素(已排序)大于新元素,将该元素移到下一位置
⒋ 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
⒌ 将新元素插入到下一位置中
⒍ 重复步骤2~5
c语言通过函数调用实现选择排序法:
1、写一个简单选择排序法的函数名,包含参数。int SelectSort(int * ListData,int ListLength);
2、写两个循环,在循环中应用简单选择插入排序:
int SelectSort(int * ListData,int ListLength)
{
int i , j ;
int length = ListLength;
for(i=0;i=length-2;i++)
{
int k = i;
for(j=i+1;j=length-1;j++)
{
if(ListData[k]ListData[j])
{
k=j;
}
}
if(k!=i)
{
int tmp = ListData[i];
ListData[i] = ListData[k];
ListData[k] = tmp;
}
}
return 0;
}
3、对编好的程序进行测试,得出测试结果:
int main()
{
int TestData[5] = {34,15,6,89,67};
int i = 0;
printf("排序之前的结果\n");
for(i = 0;i5;i++)
printf("|%d|",TestData[i]);
int retData = SelectSort(TestData,5);
printf("排序之后的结果:\n");
for(i = 0;i5;i++)
printf("|%d|",TestData[i]);
return 0;
}
4、简单选择排序中,需要移动的记录次数比较少,主要的时间消耗在对于数据的比较次数。基本上,在比较的时候,消耗的时间复杂度为:n*n。
用插入排序做了一下
#include stdlib.h
typedef struct data
{
int value;
struct data *next;
}data;
int sort_link(data **op_list)
{
data *p1 = NULL; // 当前待排序的节点
data *p2 = NULL; // 待排序链表表头
data *q = NULL; // 有序链表表头
data *t1 = NULL; // 插入节点的前一个节点
data *t2 = NULL; // 插入节点的后一个节点
// 入参检查
if (NULL == op_list || NULL == *op_list)
{
return -1;
}
p1 = *op_list;
while (NULL != p1)
{
p2 = p1-next; // 记录待排序链表下一个节点的位置
p1-next = NULL; // 把当前节点从链表中分离出来
t2 = q;
while (NULL != t2)
{
if (t2-value = p1-value)
{
t1 = t2;
t2 = t2-next;
}
else if (t2 == q)
{
// 插到有序链表的首部
p1-next = q;
q = p1;
break;
}
else
{
// 将当前节点插到t1和t2之间
t1-next = p1;
p1-next = t2;
break;
}
}
if (NULL == t2)
{
if (NULL == t1)
{
// 插入的是第一个节点
q = p1;
}
else
{
// 插到有序链表的末尾
t1-next = p1;
}
}
p1 = p2;
}
*op_list = q;
return 0;
}
// 测试函数入口
int main()
{
data *list = NULL;
data *p = NULL;
int num = 4;
for (; num 0; --num)
{
p = (data*)malloc(sizeof(data));
p-value = num;
p-next = list;
list = p;
}
sort_link(list);
return 0;
}
C语言中没有预置的sort函数。如果在C语言中,遇到有调用sort函数,就是自定义的一个函数,功能一般用于排序。
一、可以编写自己的sort函数。
如下函数为将整型数组从小到大排序。
void sort(int *a, int l)//a为数组地址,l为数组长度。
{
int i, j;
int v;
//排序主体
for(i = 0; i l - 1; i ++)
for(j = i+1; j l; j ++)
{
if(a[i] a[j])//如前面的比后面的大,则交换。
{
v = a[i];
a[i] = a[j];
a[j] = v;
}
}}
对于这样的自定义sort函数,可以按照定义的规范来调用。
二、C语言有自有的qsort函数。
功 能: 使用快速排序例程进行排序
头文件:stdlib.h
原型: void qsort(void *base,int nelem,int width,int (*fcmp)(const void *,const void *));
参数:
1 待排序数组首地址
2 数组中待排序元素数量
3 各元素的占用空间大小
4 指向函数的指针,用于确定排序的顺序
这个函数必须要自己写比较函数,即使要排序的元素是int,float一类的C语言基础类型。
以下是qsort的一个例子:
#includestdio.h
#includestdlib.h
int comp(const void*a,const void*b)//用来做比较的函数。
{
return *(int*)a-*(int*)b;
}
int main()
{
int a[10] = {2,4,1,5,5,3,7,4,1,5};//乱序的数组。
int i;
qsort(a,n,sizeof(int),comp);//调用qsort排序
for(i=0;i10;i++)//输出排序后的数组
{
printf("%d\t",array[i]);
}
return 0;
}
扩展资料:
sort函数的用法(C++排序库函数的调用)
对数组进行排序,在c++中有库函数帮我们实现,这们就不需要我们自己来编程进行排序了。
(一)为什么要用c++标准库里的排序函数
Sort()函数是c++一种排序方法之一,学会了这种方法也打消我学习c++以来使用的冒泡排序和选择排序所带来的执行效率不高的问题!因为它使用的排序方法是类似于快排的方法,时间复杂度为n*log2(n),执行效率较高!
(二)c++标准库里的排序函数的使用方法
I)Sort函数包含在头文件为#includealgorithm的c++标准库中,调用标准库里的排序方法可以不必知道其内部是如何实现的,只要出现我们想要的结果即可!
II)Sort函数有三个参数:
(1)第一个是要排序的数组的起始地址。
(2)第二个是结束的地址(最后一位要排序的地址的下一地址)
(3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。
Sort函数使用模板:
Sort(start,end,排序方法)
下面就具体使用sort()函数结合对数组里的十个数进行排序做一个说明!
例一:sort函数没有第三个参数,实现的是从小到大
#includeiostream
#includealgorithm
using namespace std;
int main()
{
int a[10]={9,6,3,8,5,2,7,4,1,0};
for(int i=0;i10;i++)
couta[i]endl;
sort(a,a+11);
for(int i=0;i10;i++)
couta[i]endl;
return 0;
}
编译器
GCC,GNU组织开发的开源免费的编译器
MinGW,Windows操作系统下的GCC
Clang,开源的BSD协议的基于LLVM的编译器
Visual C++ :: cl.exe,Microsoft VC++自带的编译器
集成开发环境
CodeBlocks,开源免费的C/C++ IDE
CodeLite,开源、跨平台的C/C++集成开发环境
Orwell Dev-C++,可移植的C/C++IDE
C-Free
Light Table
Visual Studio系列
Hello World
参考资料:百度百科-sort函数