C语言排序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言排序相关的知识,希望对你有一定的参考价值。
求各种排序的思路与C程序实例,要求思路详细(相当详细.),程序要有注释.
最重要的是思路!我要算法思想详细描述!!!
//起泡排序,简单选择排序,树形选择排序,堆排序,先自己看看吧,
//看不懂可以再问身边的人或者查资料,既然可以上网,我相信你所在的地方信息流通方式应该还行,所有的程序全部在VC++6.0下编译通过
//希尔排序
#include<stdio.h>
typedef int InfoType; // 定义其它数据项的类型
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
#define MAXSIZE 20 // 一个用作示例的小顺序表的最大长度
typedef int KeyType; // 定义关键字类型为整型
struct RedType // 记录类型
KeyType key; // 关键字项
InfoType otherinfo; // 其它数据项,具体类型在主程中定义
;
struct SqList // 顺序表类型
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length; // 顺序表长度
;
void ShellInsert(SqList &L,int dk)
// 对顺序表L作一趟希尔插入排序。本算法是和一趟直接插入排序相比,
// 作了以下修改:
// 1.前后记录位置的增量是dk,而不是1;
// 2.r[0]只是暂存单元,不是哨兵。当j<=0时,插入位置已找到。算法10.4
int i,j;
for(i=dk+1;i<=L.length;++i)
if LT(L.r[i].key,L.r[i-dk].key)
// 需将L.r[i]插入有序增量子表
L.r[0]=L.r[i]; // 暂存在L.r[0]
for(j=i-dk;j>0&<(L.r[0].key,L.r[j].key);j-=dk)
L.r[j+dk]=L.r[j]; // 记录后移,查找插入位置
L.r[j+dk]=L.r[0]; // 插入
void print(SqList L)
int i;
for(i=1;i<=L.length;i++)
printf("%d ",L.r[i].key);
printf("\n");
void print1(SqList L)
int i;
for(i=1;i<=L.length;i++)
printf("(%d,%d)",L.r[i].key,L.r[i].otherinfo);
printf("\n");
void ShellSort(SqList &L,int dlta[],int t)
// 按增量序列dlta[0..t-1]对顺序表L作希尔排序。算法10.5
int k;
for(k=0;k<t;++k)
ShellInsert(L,dlta[k]); // 一趟增量为dlta[k]的插入排序
printf("第%d趟排序结果: ",k+1);
print(L);
#define N 10
#define T 3
void main()
RedType d[N]=49,1,38,2,65,3,97,4,76,5,13,6,27,7,49,8,55,9,4,10;
SqList l;
int dt[T]=5,3,1; // 增量序列数组
for(int i=0;i<N;i++)
l.r[i+1]=d[i];
l.length=N;
printf("排序前: ");
print(l);
ShellSort(l,dt,T);
printf("排序后: ");
print1(l);
/*****************************************************************/
//链式基数排序
typedef int InfoType; // 定义其它数据项的类型
typedef int KeyType; // 定义RedType类型的关键字为整型
struct RedType // 记录类型(同c10-1.h)
KeyType key; // 关键字项
InfoType otherinfo; // 其它数据项
;
typedef char KeysType; // 定义关键字类型为字符型
#include<string.h>
#include<ctype.h>
#include<malloc.h> // malloc()等
#include<limits.h> // INT_MAX等
#include<stdio.h> // EOF(=^Z或F6),NULL
#include<stdlib.h> // atoi()
#include<io.h> // eof()
#include<math.h> // floor(),ceil(),abs()
#include<process.h> // exit()
#include<iostream.h> // cout,cin
// 函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status; // Status是函数的类型,其值是函数结果状态代码,如OK等
typedef int Boolean; // Boolean是布尔类型,其值是TRUE或FALSE
#define MAX_NUM_OF_KEY 8 // 关键字项数的最大值
#define RADIX 10 // 关键字基数,此时是十进制整数的基数
#define MAX_SPACE 1000
struct SLCell // 静态链表的结点类型
KeysType keys[MAX_NUM_OF_KEY]; // 关键字
InfoType otheritems; // 其它数据项
int next;
;
struct SLList // 静态链表类型
SLCell r[MAX_SPACE]; // 静态链表的可利用空间,r[0]为头结点
int keynum; // 记录的当前关键字个数
int recnum; // 静态链表的当前长度
;
typedef int ArrType[RADIX];
void InitList(SLList &L,RedType D[],int n)
// 初始化静态链表L(把数组D中的数据存于L中)
char c[MAX_NUM_OF_KEY],c1[MAX_NUM_OF_KEY];
int i,j,max=D[0].key; // max为关键字的最大值
for(i=1;i<n;i++)
if(max<D[i].key)
max=D[i].key;
L.keynum=int(ceil(log10(max)));
L.recnum=n;
for(i=1;i<=n;i++)
L.r[i].otheritems=D[i-1].otherinfo;
itoa(D[i-1].key,c,10); // 将10进制整型转化为字符型,存入c
for(j=strlen(c);j<L.keynum;j++) // 若c的长度<max的位数,在c前补'0'
strcpy(c1,"0");
strcat(c1,c);
strcpy(c,c1);
for(j=0;j<L.keynum;j++)
L.r[i].keys[j]=c[L.keynum-1-j];
int ord(char c)
// 返回k的映射(个位整数)
return c-'0';
void Distribute(SLCell r[],int i,ArrType f,ArrType e) // 算法10.15
// 静态键表L的r域中记录已按(keys[0],…,keys[i-1])有序。本算法按
// 第i个关键字keys[i]建立RADIX个子表,使同一子表中记录的keys[i]相同。
// f[0..RADIX-1]和e[0..RADIX-1]分别指向各子表中第一个和最后一个记录
int j,p;
for(j=0;j<RADIX;++j)
f[j]=0; // 各子表初始化为空表
for(p=r[0].next;p;p=r[p].next)
j=ord(r[p].keys[i]); // ord将记录中第i个关键字映射到[0..RADIX-1]
if(!f[j])
f[j]=p;
else
r[e[j]].next=p;
e[j]=p; // 将p所指的结点插入第j个子表中
int succ(int i)
// 求后继函数
return ++i;
void Collect(SLCell r[],ArrType f,ArrType e)
// 本算法按keys[i]自小至大地将f[0..RADIX-1]所指各子表依次链接成
// 一个链表,e[0..RADIX-1]为各子表的尾指针。算法10.16
int j,t;
for(j=0;!f[j];j=succ(j)); // 找第一个非空子表,succ为求后继函数
r[0].next=f[j];
t=e[j]; // r[0].next指向第一个非空子表中第一个结点
while(j<RADIX-1)
for(j=succ(j);j<RADIX-1&&!f[j];j=succ(j)); // 找下一个非空子表
if(f[j])
// 链接两个非空子表
r[t].next=f[j];
t=e[j];
r[t].next=0; // t指向最后一个非空子表中的最后一个结点
void printl(SLList L)
// 按链表输出静态链表
int i=L.r[0].next,j;
while(i)
for(j=L.keynum-1;j>=0;j--)
printf("%c",L.r[i].keys[j]);
printf(" ");
i=L.r[i].next;
void RadixSort(SLList &L)
// L是采用静态链表表示的顺序表。对L作基数排序,使得L成为按关键字
// 自小到大的有序静态链表,L.r[0]为头结点。算法10.17
int i;
ArrType f,e;
for(i=0;i<L.recnum;++i)
L.r[i].next=i+1;
L.r[L.recnum].next=0; // 将L改造为静态链表
for(i=0;i<L.keynum;++i)
// 按最低位优先依次对各关键字进行分配和收集
Distribute(L.r,i,f,e); // 第i趟分配
Collect(L.r,f,e); // 第i趟收集
printf("第%d趟收集后:\n",i+1);
printl(L);
printf("\n");
void print(SLList L)
// 按数组序号输出静态链表
int i,j;
printf("keynum=%d recnum=%d\n",L.keynum,L.recnum);
for(i=1;i<=L.recnum;i++)
printf("keys=");
for(j=L.keynum-1;j>=0;j--)
printf("%c",L.r[i].keys[j]);
printf(" otheritems=%d next=%d\n",L.r[i].otheritems,L.r[i].next);
void Sort(SLList L,int adr[]) // 改此句(类型)
// 求得adr[1..L.length],adr[i]为静态链表L的第i个最小记录的序号
int i=1,p=L.r[0].next;
while(p)
adr[i++]=p;
p=L.r[p].next;
void Rearrange(SLList &L,int adr[]) // 改此句(类型)
// adr给出静态链表L的有序次序,即L.r[adr[i]]是第i小的记录。
// 本算法按adr重排L.r,使其有序。算法10.18(L的类型有变)
int i,j,k;
for(i=1;i<L.recnum;++i) // 改此句(类型)
if(adr[i]!=i)
j=i;
L.r[0]=L.r[i]; // 暂存记录L.r[i]
while(adr[j]!=i)
// 调整L.r[adr[j]]的记录到位直到adr[j]=i为止
k=adr[j];
L.r[j]=L.r[k];
adr[j]=j;
j=k; // 记录按序到位
L.r[j]=L.r[0];
adr[j]=j;
#define N 10
void main()
RedType d[N]=278,1,109,2,63,3,930,4,589,5,184,6,505,7,269,8,8,9,83,10;
SLList l;
int *adr;
InitList(l,d,N);
printf("排序前(next域还没赋值):\n");
print(l);
RadixSort(l);
printf("排序后(静态链表):\n");
print(l);
adr=(int*)malloc((l.recnum)*sizeof(int));
Sort(l,adr);
Rearrange(l,adr);
printf("排序后(重排记录):\n");
print(l);
/*******************************************/
//归并排序
#include<stdio.h>
typedef int InfoType; // 定义其它数据项的类型
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
#define MAXSIZE 20 // 一个用作示例的小顺序表的最大长度
typedef int KeyType; // 定义关键字类型为整型
struct RedType // 记录类型
KeyType key; // 关键字项
InfoType otherinfo; // 其它数据项,具体类型在主程中定义
;
struct SqList // 顺序表类型
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length; // 顺序表长度
;
void Merge(RedType SR[],RedType TR[],int i,int m,int n)
// 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n] 算法10.12
int j,k,l;
for(j=m+1,k=i;i<=m&&j<=n;++k) // 将SR中记录由小到大地并入TR
if LQ(SR[i].key,SR[j].key)
TR[k]=SR[i++];
else
TR[k]=SR[j++];
if(i<=m)
for(l=0;l<=m-i;l++)
TR[k+l]=SR[i+l]; // 将剩余的SR[i..m]复制到TR
if(j<=n)
for(l=0;l<=n-j;l++)
TR[k+l]=SR[j+l]; // 将剩余的SR[j..n]复制到TR
void MSort(RedType SR[],RedType TR1[],int s, int t)
// 将SR[s..t]归并排序为TR1[s..t]。算法10.13
int m;
RedType TR2[MAXSIZE+1];
if(s==t)
TR1[s]=SR[s];
else
m=(s+t)/2; // 将SR[s..t]平分为SR[s..m]和SR[m+1..t]
MSort(SR,TR2,s,m); // 递归地将SR[s..m]归并为有序的TR2[s..m]
MSort(SR,TR2,m+1,t); // 递归地将SR[m+1..t]归并为有序的TR2[m+1..t]
Merge(TR2,TR1,s,m,t); // 将TR2[s..m]和TR2[m+1..t]归并到TR1[s..t]
void MergeSort(SqList &L)
// 对顺序表L作归并排序。算法10.14
MSort(L.r,L.r,1,L.length);
void print(SqList L)
int i;
for(i=1;i<=L.length;i++)
printf("(%d,%d)",L.r[i].key,L.r[i].otherinfo);
printf("\n");
#define N 7
void main()
RedType d[N]=49,1,38,2,65,3,97,4,76,5,13,6,27,7;
SqList l;
int i;
for(i=0;i<N;i++)
l.r[i+1]=d[i];
l.length=N;
printf("排序前:\n");
print(l);
MergeSort(l);
printf("排序后:\n");
print(l);
/**********************************************/
//起泡排序
#include<string.h>
#include<ctype.h>
#include<malloc.h> // malloc()等
#include<limits.h> // INT_MAX等
#include<stdio.h> // EOF(=^Z或F6),NULL
#include<stdlib.h> // atoi()
#include<io.h> // eof()
#include<math.h> // floor(),ceil(),abs()
#include<process.h> // exit()
#include<iostream.h> // cout,cin
// 函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status;
typedef int Boolean;
#define N 8
void bubble_sort(int a[],int n)
// 将a中整数序列重新排列成自小至大有序的整数序列(起泡排序)
int i,j,t;
Status change;
for(i=n-1,change=TRUE;i>1&&change;--i)
change=FALSE;
for(j=0;j<i;++j)
if(a[j]>a[j+1])
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
change=TRUE;
void print(int r[],int n)
int i;
for(i=0;i<n;i++)
printf("%d ",r[i]);
printf("\n");
void main()
int d[N]=49,38,65,97,76,13,27,49;
printf("排序前:\n");
print(d,N);
bubble_sort(d,N);
printf("排序后:\n");
print(d,N);
/****************************************************/
//简单选择排序
#include<stdio.h>
typedef int InfoType; // 定义其它数据项的类型
#define MAXSIZE 20 // 一个用作示例的小顺序表的最大长度
typedef int KeyType; // 定义关键字类型为整型
struct RedType // 记录类型
KeyType key; // 关键字项
InfoType otherinfo; // 其它数据项,具体类型在主程中定义
;
struct SqList // 顺序表类型
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length; // 顺序表长度
;
int SelectMinKey(SqList L,int i)
// 返回在L.r[i..L.length]中key最小的记录的序号
KeyType min;
int j,k;
k=i; // 设第i个为最小
min=L.r[i].key;
for(j=i+1;j<=L.length;j++)
if(L.r[j].key<min) // 找到更小的
k=j;
min=L.r[j].key;
return k;
void SelectSort(SqList &L)
// 对顺序表L作简单选择排序。算法10.9
int i,j;
RedType t;
for(i=1;i<L.length;++i)
// 选择第i小的记录,并交换到位
j=SelectMinKey(L,i); // 在L.r[i..L.length]中选择key最小的记录
if(i!=j)
// 与第i个记录交换
t=L.r[i];
L.r[i]=L.r[j];
L.r[j]=t;
void print(SqList L)
int i;
for(i=1;i<=L.length;i++)
printf("(%d,%d)",L.r[i].key,L.r[i].otherinfo);
printf("\n");
#define N 8
void main()
RedType d[N]=49,1,38,2,65,3,97,4,76,5,13,6,27,7,49,8;
SqList l;
int i;
for(i=0;i<N;i++)
l.r[i+1]=d[i];
l.length=N;
printf("排序前:\n");
print(l);
SelectSort(l);
printf("排序后:\n");
print(l);
/************************************************/
//树形选择排序
#include<string.h>
#include<ctype.h>
#include<malloc.h> // malloc()等
#include<limits.h> // INT_MAX等
#include<stdio.h> // EOF(=^Z或F6),NULL
#include<stdlib.h> // atoi()
#include<io.h> // eof()
#include<math.h> // floor(),ceil(),abs()
#include<process.h> // exit()
#include<iostream.h> // cout,cin
// 函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status; // Status是函数的类型,其值是函数结果状态代码,如OK等
typedef int Boolean; // Boolean是布尔类型,其值是TRUE或FALSE
typedef int InfoType; // 定义其它数据项的类型
#define MAXSIZE 20 // 一个用作示例的小顺序表的最大长度
typedef int KeyType; // 定义关键字类型为整型
struct RedType // 记录类型
KeyType key; // 关键字项
InfoType otherinfo; // 其它数据项,具体类型在主程中定义
;
struct SqList // 顺序表类型
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length; // 顺序表长度
;
void TreeSort(SqList &L)
// 树形选择排序
int i,j,j1,k,k1,l,n=L.length;
RedType *t;
l=(int)ceil(log(n)/log(2))+1; // 完全二叉树的层数
k=(int)pow(2,l)-1; // l层完全二叉树的结点总数
k1=(int)pow(2,l-1)-1; // l-1层完全二叉树的结点总数
t=(RedType*)malloc(k*sizeof(RedType)); // 二叉树采用顺序存储结构
for(i=1;i<=n;i++) // 将L.r赋给叶子结点
t[k1+i-1]=L.r[i];
for(i=k1+n;i<k;i++) // 给多余的叶子的关键字赋无穷大
t[i].key=INT_MAX;
j1=k1;
j=k;
while(j1)
// 给非叶子结点赋值
for(i=j1;i<j;i+=2)
t[i].key<t[i+1].key?(t[(i+1)/2-1]=t[i]):(t[(i+1)/2-1]=t[i+1]);
j=j1;
j1=(j1-1)/2;
for(i=0;i<n;i++)
L.r[i+1]=t[0]; // 将当前最小值赋给L.r[i]
j1=0;
for(j=1;j<l;j++) // 沿树根找结点t[0]在叶子中的序号j1
t[2*j1+1].key==t[j1].key?(j1=2*j1+1):(j1=2*j1+2);
t[j1].key=INT_MAX;
while(j1)
j1=(j1+1)/2-1; // 序号为j1的结点的双亲结点序号
t[2*j1+1].key<=t[2*j1+2].key?(t[j1]=t[2*j1+1]):(t[j1]=t[2*j1+2]);
free(t);
void print(SqList L)
int i;
for(i=1;i<=L.length;i++)
printf("(%d,%d)",L.r[i].key,L.r[i].otherinfo);
printf("\n");
#define N 8
void main()
RedType d[N]=49,1,38,2,65,3,97,4,76,5,13,6,27,7,49,8;
SqList l;
int i;
for(i=0;i<N;i++)
l.r[i+1]=d[i];
l.length=N;
printf("排序前:\n");
print(l);
TreeSort(l);
printf("排序后:\n");
print(l);
/****************************/
//堆排序
#include<stdio.h>
typedef int InfoType; // 定义其它数据项的类型
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
#define MAXSIZE 20 // 一个用作示例的小顺序表的最大长度
typedef int KeyType; // 定义关键字类型为整型
struct RedType // 记录类型
KeyType key; // 关键字项
InfoType otherinfo; // 其它数据项,具体类型在主程中定义
;
struct SqList // 顺序表类型
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length; // 顺序表长度
;
typedef SqList HeapType; // 堆采用顺序表存储表示
void HeapAdjust(HeapType &H,int s,int m) // 算法10.10
// 已知H.r[s..m]中记录的关键字除H.r[s].key之外均满足堆的定义,本函数
// 调整H.r[s]的关键字,使H.r[s..m]成为一个大顶堆(对其中记录的关键字而言)
RedType rc;
int j;
rc=H.r[s];
for(j=2*s;j<=m;j*=2)
// 沿key较大的孩子结点向下筛选
if(j<m&<(H.r[j].key,H.r[j+1].key))
++j; // j为key较大的记录的下标
if(!LT(rc.key,H.r[j].key))
break; // rc应插入在位置s上
H.r[s]=H.r[j];
s=j;
H.r[s]=rc; // 插入
void HeapSort(HeapType &H)
// 对顺序表H进行堆排序。算法10.11
RedType t;
int i;
for(i=H.length/2;i>0;--i) // 把H.r[1..H.length]建成大顶堆
HeapAdjust(H,i,H.length);
for(i=H.length;i>1;--i)
// 将堆顶记录和当前未经排序子序列H.r[1..i]中最后一个记录相互交换
t=H.r[1];
H.r[1]=H.r[i];
H.r[i]=t;
HeapAdjust(H,1,i-1); // 将H.r[1..i-1]重新调整为大顶堆
void print(HeapType H)
int i;
for(i=1;i<=H.length;i++)
printf("(%d,%d)",H.r[i].key,H.r[i].otherinfo);
printf("\n");
#define N 8
void main()
RedType d[N]=49,1,38,2,65,3,97,4,76,5,13,6,27,7,49,8;
HeapType h;
int i;
for(i=0;i<N;i++)
h.r[i+1]=d[i];
h.length=N;
printf("排序前:\n");
print(h);
HeapSort(h);
printf("排序后:\n");
print(h);
参考技术A 排序算法所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
分类
在计算机科学所使用的排序算法通常被分类为:
计算的复杂度(最差、平均、和最好表现),依据串列(list)的大小(n)。一般而言,好的表现是O。(n log n),且坏的行为是Ω(n2)。对於一个排序理想的表现是O(n)。仅使用一个抽象关键比较运算的排序算法总平均上总是至少需要Ω(n log n)。
记忆体使用量(以及其他电脑资源的使用)
稳定度:稳定排序算法会依照相等的关键(换言之就是值)维持纪录的相对次序。也就是一个排序算法是稳定的,就是当有两个有相等关键的纪录R和S,且在原本的串列中R出现在S之前,在排序过的串列中R也将会是在S之前。
一般的方法:插入、交换、选择、合并等等。交换排序包含冒泡排序(bubble sort)和快速排序(quicksort)。选择排序包含shaker排序和堆排序(heapsort)。
当相等的元素是无法分辨的,比如像是整数,稳定度并不是一个问题。然而,假设以下的数对将要以他们的第一个数字来排序。
(4, 1) (3, 1) (3, 7) (5, 6)
在这个状况下,有可能产生两种不同的结果,一个是依照相等的键值维持相对的次序,而另外一个则没有:
(3, 1) (3, 7) (4, 1) (5, 6) (维持次序)
(3, 7) (3, 1) (4, 1) (5, 6) (次序被改变)
不稳定排序算法可能会在相等的键值中改变纪录的相对次序,但是稳定排序算法从来不会如此。不稳定排序算法可以被特别地时作为稳定。作这件事情的一个方式是人工扩充键值的比较,如此在其他方面相同键值的两个物件间之比较,就会被决定使用在原先资料次序中的条目,当作一个同分决赛。然而,要记住这种次序通常牵涉到额外的空间负担。
[编辑]排列算法列表
在这个表格中,n是要被排序的纪录数量以及k是不同键值的数量。
[编辑]稳定的
冒泡排序(bubble sort) — O(n2)
鸡尾酒排序 (Cocktail sort, 双向的冒泡排序) — O(n2)
插入排序 (insertion sort)— O(n2)
桶排序 (bucket sort)— O(n); 需要 O(k) 额外 记忆体
计数排序 (counting sort) — O(n+k); 需要 O(n+k) 额外 记忆体
归并排序 (merge sort)— O(n log n); 需要 O(n) 额外记忆体
原地归并排序 — O(n2)
二叉树排序 (Binary tree sort) — O(n log n); 需要 O(n) 额外记忆体
鸽巢排序 (Pigeonhole sort) — O(n+k); 需要 O(k) 额外记忆体
基数排序 (radix sort)— O(n·k); 需要 O(n) 额外记忆体
Gnome sort — O(n2)
Library sort — O(n log n) with high probability, 需要 (1+ε)n 额外记忆体
[编辑]不稳定
选择排序 (selection sort)— O(n2)
希尔排序 (shell sort)— O(n log n) 如果使用最佳的现在版本
Comb sort — O(n log n)
堆排序 (heapsort)— O(n log n)
Smoothsort — O(n log n)
快速排序 (quicksort)— O(n log n) 期望时间, O(n2) 最坏情况; 对於大的、乱数串列一般相信是最快的已知排序
Introsort — O(n log n)
Patience sorting — O(n log n + k) 最外情况时间, 需要 额外的 O(n + k) 空间, 也需要找到最长的递增子序列(longest increasing subsequence)
[编辑]不实用的排序算法
Bogo排序 — O(n × n!) 期望时间, 无穷的最坏情况。
Stupid sort — O(n3); 递回版本需要 O(n2) 额外记忆体
Bead sort — O(n) or O(√n), 但需要特别的硬体
Pancake sorting — O(n), 但需要特别的硬体
[编辑]排序的算法
排序的算法有很多,对空间的要求及其时间效率也不尽相同。下面列出了一些常见的排序算法。这里面插入排序和冒泡排序又被称作简单排序,他们对空间的要求不高,但是时间效率却不稳定;而后面三种排序相对于简单排序对空间的要求稍高一点,但时间效率却能稳定在很高的水平。基数排序是针对关键字在一个较小范围内的排序算法。
插入排序
冒泡排序
选择排序
快速排序
堆排序
归并排序
基数排序
希尔排序
[编辑]插入排序
插入排序是这样实现的:
首先新建一个空列表,用于保存已排序的有序数列(我们称之为"有序列表")。
从原数列中取出一个数,将其插入"有序列表"中,使其仍旧保持有序状态。
重复2号步骤,直至原数列为空。
插入排序的平均时间复杂度为平方级的,效率不高,但是容易实现。它借助了"逐步扩大成果"的思想,使有序列表的长度逐渐增加,直至其长度等于原列表的长度。
[编辑]冒泡排序
冒泡排序是这样实现的:
首先将所有待排序的数字放入工作列表中。
从列表的第一个数字到倒数第二个数字,逐个检查:若某一位上的数字大于他的下一位,则将它与它的下一位交换。
重复2号步骤,直至再也不能交换。
冒泡排序的平均时间复杂度与插入排序相同,也是平方级的,但也是非常容易实现的算法。
[编辑]选择排序
选择排序是这样实现的:
设数组内存放了n个待排数字,数组下标从1开始,到n结束。
i=1
从数组的第i个元素开始到第n个元素,寻找最小的元素。
将上一步找到的最小元素和第i位元素交换。
如果i=n-1算法结束,否则回到第3步
选择排序的平均时间复杂度也是O(n²)的。
[编辑]快速排序
现在开始,我们要接触高效排序算法了。实践证明,快速排序是所有排序算法中最高效的一种。它采用了分治的思想:先保证列表的前半部分都小于后半部分,然后分别对前半部分和后半部分排序,这样整个列表就有序了。这是一种先进的思想,也是它高效的原因。因为在排序算法中,算法的高效与否与列表中数字间的比较次数有直接的关系,而"保证列表的前半部分都小于后半部分"就使得前半部分的任何一个数从此以后都不再跟后半部分的数进行比较了,大大减少了数字间不必要的比较。但查找数据得另当别论了。
[编辑]堆排序
堆排序与前面的算法都不同,它是这样的:
首先新建一个空列表,作用与插入排序中的"有序列表"相同。
找到数列中最大的数字,将其加在"有序列表"的末尾,并将其从原数列中删除。
重复2号步骤,直至原数列为空。
堆排序的平均时间复杂度为nlogn,效率高(因为有堆这种数据结构以及它奇妙的特征,使得"找到数列中最大的数字"这样的操作只需要O(1)的时间复杂度,维护需要logn的时间复杂度),但是实现相对复杂(可以说是这里7种算法中比较难实现的)。
看起来似乎堆排序与插入排序有些相像,但他们其实是本质不同的算法。至少,他们的时间复杂度差了一个数量级,一个是平方级的,一个是对数级的。
[编辑]平均时间复杂度
插入排序 O(n2)
冒泡排序 O(n2)
选择排序 O(n2)
快速排序 O(n log n)
堆排序 O(n log n)
归并排序 O(n log n)
基数排序 O(n)
希尔排序 O(n1.25)
参考资料:http://www.wiki.cn/wiki/排序算法
参考技术B 太多了,写不下://1.冒泡法:
#include <iostream.h>
void BubbleSort(int* pData,int Count)
int iTemp;
for(int i=1;i<Count;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[] = ;
BubbleSort(data,7);
for (int i=0;i<7;i++)
cout<<data<<" ";
cout<<"\n";
//2.交换法:
交换法的程序最清晰简单,每次用当前的元素一一的同其后的元素比较并交换。
#include <iostream.h>
void ExchangeSort(int* pData,int Count)
int iTemp;
for(int i=0;i<Count-1;i++)
for(int j=i+1;j<Count;j++)
if(pData[j]<pData)
iTemp = pData;
pData = pData[j];
pData[j] = iTemp;
void main()
int data[] = ;
ExchangeSort(data,7);
for (int i=0;i<7;i++)
cout<<data<<" ";
cout<<"\n";
3.选择法:
现在我们终于可以看到一点希望:选择法,这种方法提高了一点性能(某些情况下)
这种方法类似我们人为的排序习惯:从数据中选择最小的同第一个值交换,在从省下的部分中
选择最小的与第二个交换,这样往复下去。
#include <iostream.h>
void SelectSort(int* pData,int Count)
int iTemp;
int iPos;
for(int i=0;i<Count-1;i++)
iTemp = pData;
iPos = i;
for(int j=i+1;j<Count;j++)
if(pData[j]<iTemp)
iTemp = pData[j];
iPos = j;
pData[iPos] = pData;
pData = iTemp;
void main()
int data[] = ;
SelectSort(data,7);
for (int i=0;i<7;i++)
cout<<data<<" ";
cout<<"\n";
4.插入法:
插入法较为复杂,它的基本工作原理是抽出牌,在前面的牌中寻找相应的位置插入,然后继续下一张
#include <iostream.h>
void InsertSort(int* pData,int Count)
int iTemp;
int iPos;
for(int i=1;i<Count;i++)
iTemp = pData;
iPos = i-1;
while((iPos>=0) && (iTemp<pData[iPos]))
pData[iPos+1] = pData[iPos];
iPos--;
pData[iPos+1] = iTemp;
void main()
int data[] = ;
InsertSort(data,7);
for (int i=0;i<7;i++)
cout<<data<<" ";
cout<<"\n";
1.快速排序:
#include <iostream.h>
void run(int* pData,int left,int right)
int i,j;
int middle,iTemp;
i = left;
j = right;
middle = pData[(left+right)/2]; //求中间值
do
while((pData<middle) && (i<right))//从左扫描大于中值的数
i++;
while((pData[j]>middle) && (j>left))//从右扫描大于中值的数
j--;
if(i<=j)//找到了一对值
//交换
iTemp = pData;
pData = pData[j];
pData[j] = iTemp;
i++;
j--;
while(i<=j);//如果两边扫描的下标交错,就停止(完成一次)
//当左边部分有值(left<j),递归左半边
if(left<j)
run(pData,left,j);
//当右边部分有值(right>i),递归右半边
if(right>i)
run(pData,i,right);
void QuickSort(int* pData,int Count)
run(pData,0,Count-1);
void main()
int data[] = ;
QuickSort(data,7);
for (int i=0;i<7;i++)
cout<<data<<" ";
cout<<"\n";
1.双向冒泡:
通常的冒泡是单向的,而这里是双向的,也就是说还要进行反向的工作。
代码看起来复杂,仔细理一下就明白了,是一个来回震荡的方式。
写这段代码的作者认为这样可以在冒泡的基础上减少一些交换(我不这么认为,也许我错了)。
反正我认为这是一段有趣的代码,值得一看。
#include <iostream.h>
void Bubble2Sort(int* pData,int Count)
int iTemp;
int left = 1;
int right =Count -1;
int t;
do
//正向的部分
for(int i=right;i>=left;i--)
if(pData<pData[i-1])
iTemp = pData;
pData = pData[i-1];
pData[i-1] = iTemp;
t = i;
left = t+1;
//反向的部分
for(i=left;i<right+1;i++)
if(pData<pData[i-1])
iTemp = pData;
pData = pData[i-1];
pData[i-1] = iTemp;
t = i;
right = t-1;
while(left<=right);
void main()
int data[] = ;
Bubble2Sort(data,7);
for (int i=0;i<7;i++)
cout<<data<<" ";
cout<<"\n";
2.SHELL排序
这个排序非常复杂,看了程序就知道了。
首先需要一个递减的步长,这里我们使用的是9、5、3、1(最后的步长必须是1)。
工作原理是首先对相隔9-1个元素的所有内容排序,然后再使用同样的方法对相隔5-1个元素的排序
以次类推。
#include <iostream.h>
void ShellSort(int* pData,int Count)
int step[4];
step[0] = 9;
step[1] = 5;
step[2] = 3;
step[3] = 1;
int iTemp;
int k,s,w;
for(int i=0;i<4;i++)
k = step;
s = -k;
for(int j=k;j<Count;j++)
iTemp = pData[j];
w = j-k;//求上step个元素的下标
if(s ==0)
s = -k;
s++;
pData[s] = iTemp;
while((iTemp<pData[w]) && (w>=0) && (w<=Count))
pData[w+k] = pData[w];
w = w-k;
pData[w+k] = iTemp;
void main()
int data[] = ;
ShellSort(data,12);
for (int i=0;i<12;i++)
cout<<data<<" ";
cout<<"\n";
参考技术C 最有名的当然是冒泡排序了
一个列子:字符排序
#include <stdio.h>
#include <string.h>
void str(char *state[])
char *temp;
for(int i=0;i<5;i++)
for(int j=0;j<5-i-1;j++)
if(strcmp(state[j],state[j+1])>0)
temp=state[j];
state[j]=state[j+1];
state[j+1]=temp;
printf("排序后的顺序是:\n");
for(i=1;i<=5;i++)
printf("%d. %s.\n",i,state[i-1]);
void main()
char *state[5]="China","USA","England","Germany","France";
printf("排序前的顺序是:\n");
for(int i=1;i<=5;i++)
printf("%d. %s.\n",i,state[i-1]);
printf("\n");
str(state);
参考技术D 分太少了, 才50分.
C语言冒泡排序法
如何更容易理解掌握冒泡排序法, 我是一个学c语言没多久的人 ,对for循环的嵌套不太容易了解 谁能给我详细而简单地说说如何学会冒泡排序法
冒泡排序每一趟排序把最大的放在最右边。
比如:
87 12 56 45 78
87和12交换:12 87 56 45 78
87和56交换: 56 87 45 78
87和45交换: 45 87 78
87和78交换: 78 87
到此第一趟排序结束,接下来的每一趟排序都是这样。
#include<stdio.h>void Print(int *num, int n)
int i;
for(i = 0; i < n; i++)
printf("%d ", num[i]);
puts("\\n");
return;
void Bubble_Sort(int *num, int n)
int i, j;
for(i = 0; i < n; i++)
for(j = 0; i + j < n - 1; j++)
if(num[j] > num[j + 1])
int temp = num[j];
num[j] = num[j + 1];
num[j + 1] = temp;
Print(num, n);
return;
int main()
int num[8] = 87, 12, 56, 45, 78;
Bubble_Sort(num, 5);
return 0;
追问
如果要学会冒泡排序法 应该背下来运用就OK了吧
追答对,冒泡排序基本上都这么写的。
参考技术A#include<stdio.h>
void main()
int a[10];
int i,j,t;
printf("input 10 numbers:\\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(j=0;j<9;j++) /*进行9次循环 实现9趟比较*/
for(i=0;i<9-j;i++) /*在每一趟中进行9-j次比较*/
if(a[i]>a[i+1]) /*相邻两个数比较,想降序只要改成a[i]<a[i+1]*/
t=a[i];
a[i]=a[i+1];
a[i+1]=t;
printf("the sorted numbers:\\n");
for(i=0;i<10;i++)
printf(" %d",a[i]);
扩展资料:
冒泡排序算法的运作
1、比较相邻的元素。如果第一个比第二个大(小),就交换他们两个。
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大(小)的数。
3、针对所有的元素重复以上的步骤,除了最后已经选出的元素(有序)。
4、持续每次对越来越少的元素(无序元素)重复上面的步骤,直到没有任何一对数字需要比较,则序列最终有序。
简单的表示
#include <stdio.h>
void swap(int *i, int *j)
int temp = *i;
*i = *j;
*j = temp;
int main()
int a[10] = 2,1,4,5,6,9,7,8,7,7;
int i,j;
for (i = 0; i < 10; i++)
for (j = 9; j > i; j--)//从后往前冒泡
if (a[j] < a[j-1])
swap(&a[j], &a[j-1]);
for (i = 0; i < 10; i++)
printf("%d\\n", a[i]);
return 0;
参考资料来源:冒泡排序-百度百科
参考技术B main()int i,j,temp;
int a[10];
for(i=0;i<10;i++)
scanf ("%d,",&a[i]);
for(j=0;j<=9;j++)
for (i=0;i<10-j;i++)
if (a[i]>a[i+1])
temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
for(i=1;i<11;i++)
printf("%5d,",a[i] );
printf("\n");
--------------
冒泡算法
冒泡排序的算法分析与改进
交换排序的基本思想是:两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。
应用交换排序基本思想的主要排序方法有:冒泡排序和快速排序。
冒泡排序
1、排序方法
将被排序的记录数组R[1..n]垂直排列,每个记录R看作是重量为R.key的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R:凡扫描到违反本原则的轻气泡,就使其向上"飘浮"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。
(1)初始
R[1..n]为无序区。
(2)第一趟扫描
从无序区底部向上依次比较相邻的两个气泡的重量,若发现轻者在下、重者在上,则交换二者的位置。即依次比较(R[n],R[n-1]),(R[n-1],R[n-2]),…,(R[2],R[1]);对于每对气泡(R[j+1],R[j]),若R[j+1].key<R[j].key,则交换R[j+1]和R[j]的内容。
第一趟扫描完毕时,"最轻"的气泡就飘浮到该区间的顶部,即关键字最小的记录被放在最高位置R[1]上。
(3)第二趟扫描
扫描R[2..n]。扫描完毕时,"次轻"的气泡飘浮到R[2]的位置上……
最后,经过n-1 趟扫描可得到有序区R[1..n]
注意:
第i趟扫描时,R[1..i-1]和R[i..n]分别为当前的有序区和无序区。扫描仍是从无序区底部向上直至该区顶部。扫描完毕时,该区中最轻气泡飘浮到顶部位置R上,结果是R[1..i]变为新的有序区。
2、冒泡排序过程示例
对关键字序列为49 38 65 97 76 13 27 49的文件进行冒泡排序的过程
3、排序算法
(1)分析
因为每一趟排序都使有序区增加了一个气泡,在经过n-1趟排序之后,有序区中就有n-1个气泡,而无序区中气泡的重量总是大于等于有序区中气泡的重量,所以整个冒泡排序过程至多需要进行n-1趟排序。
若在某一趟排序中未发现气泡位置的交换,则说明待排序的无序区中所有气泡均满足轻者在上,重者在下的原则,因此,冒泡排序过程可在此趟排序后终止。为此,在下面给出的算法中,引入一个布尔量exchange,在每趟排序开始前,先将其置为FALSE。若排序过程中发生了交换,则将其置为TRUE。各趟排序结束时检查exchange,若未曾发生过交换则终止算法,不再进行下一趟排序。
(2)具体算法
void BubbleSort(SeqList R)
//R(l..n)是待排序的文件,采用自下向上扫描,对R做冒泡排序
int i,j;
Boolean exchange; //交换标志
for(i=1;i<n;i++) //最多做n-1趟排序
exchange=FALSE; //本趟排序开始前,交换标志应为假
for(j=n-1;j>=i;j--) //对当前无序区R[i..n]自下向上扫描
if(R[j+1].key<R[j].key)//交换记录
R[0]=R[j+1]; //R[0]不是哨兵,仅做暂存单元
R[j+1]=R[j];
R[j]=R[0];
exchange=TRUE; //发生了交换,故将交换标志置为真
if(!exchange) //本趟排序未发生交换,提前终止算法
return;
//endfor(外循环)
//BubbleSort
4、算法分析
(1)算法的最好时间复杂度
若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数C和记录移动次数M均达到最小值:
Cmin=n-1
Mmin=0。
冒泡排序最好的时间复杂度为O(n)。
(2)算法的最坏时间复杂度
若初始文件是反序的,需要进行n-1趟排序。每趟排序要进行n-i次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
Cmax=n(n-1)/2=O(n2)
Mmax=3n(n-1)/2=O(n2)
冒泡排序的最坏时间复杂度为O(n2)。
(3)算法的平均时间复杂度为O(n2)
虽然冒泡排序不一定要进行n-1趟,但由于它的记录移动次数较多,故平均时间性能比直接插入排序要差得多。
(4)算法稳定性
冒泡排序是就地排序,且它是稳定的。
5、算法改进
上述的冒泡排序还可做如下的改进:
(1)记住最后一次交换发生位置lastExchange的冒泡排序
在每趟扫描中,记住最后一次交换发生的位置lastExchange,(该位置之前的相邻记录均已有序)。下一趟排序开始时,R[1..lastExchange-1]是有序区,R[lastExchange..n]是无序区。这样,一趟排序可能使当前有序区扩充多个记录,从而减少排序的趟数。具体算法【参见习题】。
(2) 改变扫描方向的冒泡排序
①冒泡排序的不对称性
能一趟扫描完成排序的情况:
只有最轻的气泡位于R[n]的位置,其余的气泡均已排好序,那么也只需一趟扫描就可以完成排序。
【例】对初始关键字序列12,18,42,44,45,67,94,10就仅需一趟扫描。
需要n-1趟扫描完成排序情况:
当只有最重的气泡位于R[1]的位置,其余的气泡均已排好序时,则仍需做n-1趟扫描才能完成排序。
【例】对初始关键字序列:94,10,12,18,42,44,45,67就需七趟扫描。
②造成不对称性的原因
每趟扫描仅能使最重气泡"下沉"一个位置,因此使位于顶端的最重气泡下沉到底部时,需做n-1趟扫描。
③改进不对称性的方法
在排序过程中交替改变扫描方向,可改进不对称性
复制过来的! 参考技术C //以下以四个数字的给举例,便于理解;
#include <stdio.h>
main()
int i; //定义i变量,i代表外层for循环--比较轮数;
int k; //定义k变量,k代表内层for循环--比较次数;
int t; //定义t变量,t代表临时变量,临时存放比较的结果中较大的数字,通过赋值的方式切换数字的排序;
int a[] = 30,3,6,10; //定义数组,数组是本次要排序的数字组合;注意此处数组中一共4个数字所以 理论上是 a[4]=30,3,6,10;
//初试化i=1;并判断i是否小于等于3; 如果符合条件 那么进入for循环;(4个数字,两两对比需要进行3轮对比,i就代表了轮数;i需要经过 1,2,3 三轮的赋值;i=4的时候会跳出for循环)
for(i=1; i<=3; i++)
//初试化k=0;并判断k是否小于等于3 -i; 如果符合条件 那么进入for循环;第一轮的时候数组一共4个数字所以需要对比3次;第二轮还有3个数字需要对比2次;第三轮仅剩2个数字需要对比1次;(特:当k=0的时候是第一次对比;k从0开始赋值是为了在for循环内当数组的键值使用;)
for(k=0; k<=3-i; k++)
//判断a[K] 的数字 是否 大于 a[K + 1 ] 的数字;假设当前是第一轮第一次对比那么a[K=0] = 30,a[K=0 + 1] = 3;
if(a[k] > a[k+1])
t = a[k]; //对上一步判断结果进行进一步处理,因为a[K] > a[K + 1 ] , 所以把a[K] 赋值给临时变量以便于 后续把这个大的数字向后平移;
a[k] = a[k+1]; //a[K + 1 ]是比较结果中比较小的数字,所以需要向前靠,向前靠就是要赋值给 a[K];空出 a[K + 1 ]便于下一步接收 较大的数字 a[K];
a[k+1] = t; //a[K + 1 ] 接收 较大的数字 a[K];
for(i=0; i<4; i++)//初试化i=0;并判断i是否小于4; 如果符合条件 那么进入for循环,i在for内做键值使用:
printf("第 %d个数字为:%d\\n",i+1,a[i]);
/*
运行结果如下:
第 1个数字为:3
第 2个数字为:6
第 3个数字为:10
第 4个数字为:30
*/ 参考技术D
C语言冒泡排序法的排序规则:
将被排序的记录数组R[1..n]垂直排列,每个记录R看作是重量为R.key的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R:凡扫描到违反本原则的轻气泡,就使其向上"飘浮"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。
初始 R[1..n]为无序区。
第一趟扫描 从无序区底部向上依次比较相邻的两个气泡的重量,若发现轻者在下、重者在上,则交换二者的位置。
即依次比较(R[n],R[n-1]),(R[n-1],R[n-2]),…,(R[2],R[1]);对于每对气泡(R[j+1],R[j]),若R[j+1].key<R[j].key,则交换R[j+1]和R[j]的内容。 第一趟扫描完毕时,"最轻"的气泡就飘浮到该区间的顶部,即关键字最小的记录被放在最高位置R[1]上。
第二趟扫描 扫描R[2..n]。
扫描完毕时,"次轻"的气泡飘浮到R[2]的位置上…… 最后,经过n-1 趟扫描可得到有序区R[1..n] 注意: 第i趟扫描时,R[1..i-1]和R[i..n]分别为当前的有序区和无序区。扫描仍是从无序区底部向上直至该区顶部。扫描完毕时,该区中最轻气泡飘浮到顶部位置R上,结果是R[1..i]变为新的有序区。
c语言冒泡排序的编程为:
#include <stdio.h>
void sort(int *a,int len)
int i=0;
int j;
int t;
for(i=0;i<len-1;i++)[1]
for(j=0;j<len-i-1;j++)
if(a[j]>a[j+1])
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
int main(int argc, char *argv[])
int a[10]=
-999,2,3,77,12,88,0,-8,99,100
;
int i=0;
sort(a,10);
for(i=0;i<10;i++)
printf("%d ",a[i]);
return 0;
以上是关于C语言排序的主要内容,如果未能解决你的问题,请参考以下文章