我们在学C的时候就已经学过好几种排序,但是数据结构还是在最后面详细介绍了不同算法的排序方式所需要的时间和空间成本,还新增了几个C基础设计里面没有的算法,这一章很重要,因为算法本就是数据结构的核心之一,好的程序员应该多理解不同算法和它们的时间复杂度和空间复杂度。特别想说一下堆的排序,里面的调试板块我都打出来了,可以直接删掉注释来当调试用。快速排序和希尔排序是数据结构里的新知识点。
#include<stdio.h>
#include<stdlib.h>
void show();
int Swap(int *a, int *b) //交换位置函数
{
int t=*a;
*a=*b;
*b= t;
}
int maopao(int *a, int n) //冒泡排序
{
int P, i;
bool flag;
for( P=n-1; P>=0; P--)
{
flag=false; //标记循环中是否发生交换,若无,则说明整个xu有序
for( i=0; i<P; i++ ){ //一起冒泡
if(a[i]>a[i+1])
{
Swap(&a[i], &a[i+1]);
flag = true;//标记发生了交换
}
}
if(flag==false) break;//若全程无交换,则跳出循环
}
for(i=0; i<n; i++)
printf("%d ", a[i]);
printf("\n");
}
int xuanze(int *a, int n) //选择排序
{
int i, j, t=0;
for(i=0; i<n; i++)
scanf("%d", &a[i]);
for( i=0; i<n-1; i++)
for(j=i+1; j<n; j++)
if(a[i]>a[j])
Swap(&a[i], &a[j]);
for( i=0; i<n; i++)
printf("%d ", a[i]);
printf("\n");
}
int PercDown(int *a, int P, int n) //堆排序--2
{
//将N个元素的数组中a[i]为根的子堆调为最大堆
int Parent, Child, j;
int X;
X = a[P]; //取出根结点
//printf("\na[(P)%d] = %d\n", P, X);
for( Parent=P; (Parent*2+1)<n; Parent=Child )
{
Child = Parent*2+1;
if((Child!=n-1)&&(a[Child]<a[Child+1]))
Child++; //Child指向左右子较大者
/*for( j=0; j<n; j++ )
printf("_%d_",a[j]);
printf("(*)\n");*/
if(X>=a[Child]) break; //找到了合适的位置
else a[Parent] = a[Child]; //下虑X
/*for( j=0; j<n; j++ )
printf("_%d_",a[j]);
printf("($)\n"); */
}
a[Parent] = X;
/*for( j=0; j<n; j++ )
printf("_%d_",a[j]);
printf("(!)\n"); */
}
int HeadSort(int *a, int n) //堆排序 --1
{
int i;
for( i=n/2-1; i>=0; i--)
PercDown( a, i, n );
for( i=n-1; i>0; i-- )
{
//删除最大项
//printf("^^^^\n");
Swap(&a[0], &a[i]);
PercDown(a, 0, i);
}
}
void InsertionSort(int *a, int N) //插入排序
{
int i, P;
int t;
for( P=1; P<N; P++){
t = a[P]; //取出未排序序列中的第一个元素
for(i=P; i>0&&a[i-1]>t; i--)
{
//printf("前:a[%d]=%d ,a[%d]=%d\n", i, a[i], i-1, a[i-1]);
a[i] = a[i-1];
//printf("后:a[%d]=%d ,a[%d]=%d\n", i, a[i], i-1, a[i-1]);
}
a[i] = t;//放进合适的位置
//printf("位置:a[%d]=%d\n", i, a[i]);
}
}
void shellsort(int *a, int n) //希尔排序
{
int Si, D, P, i;
int t;
int SE[] = {929, 505, 209, 41, 19, 7, 5, 3, 1, 0};
for( Si=0; SE[Si]>=n; Si++ )
for( D=a[Si]; D>0; D=a[++Si])
for( P=D; P<n; P++)
{
t = a[P];
for( i=P; i>=D&&a[i-D]>t; i-=D)
a[i] = a[i-D];
a[i] = t;
}
}
int Median3(int *a, int Left, int Right)
{
int Center = (Left+Right)/2;
if(a[Left]>a[Center])
Swap(&a[Left], &a[Center]);
if(a[Left]>a[Right])
Swap(&a[Left], &a[Right]);
if(a[Center]>a[Right])
Swap(&a[Center], &a[Right]);
Swap(&a[Center], &a[Right-1]);//将基准pivot藏到右边
return a[Right-1];//返回基准 pivot
}
void Qsort(int *a, int Left, int Right)
{
int pivot, cutoff, Low, Hight;
if(cutoff<=Right-Left){ //如果序列元素充分过多,进入快排
pivot = Median3(a, Left, Right);//选基准
Low=Left; Hight=Right-1;
while(1){ //将序列中比基准小的移到基准左边,打的移动到右边
while( a[++Low] <pivot );
while( a[--Hight]>pivot );
if(Low>Hight) Swap(&a[Low], &a[Hight]);
else break;
}
Swap( &a[Low], &a[Right-1] );
Qsort(a, Left, Low-1);
Qsort(a, Low+1, Right);
}
else InsertionSort(a+Left, Right-Left+1); //元素太少,用简单排序
}
///一下为归并排序代码
void Merge( int *A, int *TmpA, int L, int R, int RightEnd )
{
int LeftEnd, NumElements, Tmp;
int i;
LeftEnd = R-1;
NumElements = RightEnd-L+1;
Tmp = L;
while( L<=LeftEnd&&R<=RightEnd ){
if( A[L]<=A[R] ) TmpA[Tmp++] = A[L++]; //将左边的元素复制到TmpA
else TmpA[Tmp++] = A[R++]; //将右边的元素复制到TmpA
}
while( L<=LeftEnd ) //复制剩下的元素
TmpA[Tmp++] = A[L++];
while( R<=RightEnd )
TmpA[Tmp++] = A[R++];
for( i=0; i<NumElements; i++, RightEnd-- )
A[RightEnd] = TmpA[RightEnd]; //将有序的TmpA[]复制到A[]中
}
void Msort( int *a, int *TmpA, int L, int RightEnd )
{
int Center;
if( L<RightEnd )
{
Center = (L+RightEnd)/2;
Msort( a, TmpA, L, Center);//递归解决左边
Msort( a, TmpA, Center+1, RightEnd);//递归解决右边
Merge( a, TmpA, L, Center+1, RightEnd);//合并两段有序序列
}
}
void MergeSort( int *A, int N )
{
int *TmpA;
TmpA = (int *)malloc(N*sizeof(int));
if( TmpA != NULL )
{
Msort(A, TmpA, 0, N-1 );
free(TmpA);
}else printf("空间不足!");
}
以上为归并排序代码
int main()
{
int i, n, m=-1;
show();
while( m!=0 )
{
scanf("%d", &m);
switch(m)
{
case 1:{
printf("输入问题规模:");
scanf("%d", &n);
int a[n];
for( i=0; i<n; i++)
scanf("%d", &a[i]);
maopao( a, n );
break;
}
case 2:{
printf("输入问题规模:");
scanf("%d", &n);
int a[n];
xuanze(a, n);
break;
}
case 3:{
printf("输入问题规模:");
scanf("%d", &n);
int a[n];
for( i=0; i<n; i++)
scanf("%d", &a[i]);
HeadSort( a, n);
for( i=0; i<n; i++)
printf("%d ",a[i]);
printf("\n");
break;
}
case 4:{
printf("输入问题规模:");
scanf("%d", &n);
int a[n];
for( i=0; i<n; i++)
scanf("%d", &a[i]);
shellsort( a, n );
for( i=0; i<n; i++)
printf("%d ",a[i]);
break;
}
case 5:{
printf("输入问题规模:");
scanf("%d", &n);
int a[n];
for( i=0; i<n; i++)
scanf("%d", &a[i]);
InsertionSort( &*a, n);
for( i=0; i<n; i++)
printf("%d ", a[i]);
printf("\n");
break;
}
case 6:{
printf("输入问题规模:");
scanf("%d", &n);
int a[n];
for( i=0; i<n; i++)
scanf("%d", &a[i]);
Qsort( a, 0, n-1);
for( i=0; i<n; i++ )
printf("%d ", a[i]);
printf("\n");
break;
}
case 7:{
printf("输入问题规模:");
scanf("%d", &n);
int a[n];
for( i=0; i<n; i++)
scanf("%d", &a[i]);
MergeSort(a, n);
for( i=0; i<n; i++)
printf("%d ",a[i]);
printf("\n");
break;
}
}
printf("\n请选择菜单:");
}
return 0;
}
void show()
{
printf(" |.......选择你需要的排序方法......|\n");
printf(" | 1.冒泡排序 |\n");
printf(" | 2.选择排序 |\n");
printf(" | 3.堆排序 |\n");
printf(" | 4.希尔排序 |\n");
printf(" | 5.插入排序 |\n");
printf(" | 6.快速排序 |\n");
printf(" | 7.归并排序 |\n");
printf(" | 8.基数排序 |\n");
printf(" | 0.结束 |\n");
printf(" |.................................|\n");
printf("选择菜单:");
}
//5 4 3 2 1 10 9 8 7 6
给一下堆排序在删掉注释后的截图:
你可以根据图中序号的选择方式,结合完全二叉树来观察排序方式。
下面的演示:
编译器:DEV C++