学过编程的应该都知道,排序算法有很多种,想把每种算法的基本思想搞懂弄清确实得下一番功夫,今天我先介绍几种简单的,冒泡排序,直接插入排序和选择排序,一定要搞清的各种思想的差异。
1,冒泡排序(升序)
基本思想:
相邻的两个元素进行比较,如果前一个元素大于后一个元素,则交换二者位置,接着继续向后循环比较直到最后一个元素,这样一趟下来就可以将最大的那个元素放到最后的位置。完成之后,进行第二趟排序,循环比较直到倒数第二个元素,就可以将第二大元素放于倒数第二个位置......循环以上步骤,直到循环比较到原数组的最后两个元素,目的就达到了,下面用图进行进一步说明。
以上图片则是第一趟排序后的结果,由图可知,经过一趟冒泡后,最大的元素出现在了它最终该出现的位置。
以此类推,最后一趟排序过程为:
比较以上三幅图,我们可知道含六个元素的数组第一趟冒泡需要5次比较,第二趟需要4次交换比较,以此类推,我们可以总结出含n个元素的一组数总共需要n-1(i)趟排序,每趟排序需要比较n-1-i(j)次。
下面看一下代码实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
void bubble_sort(int arr[],int sz)
{
int i=0;
int j=0;
for(i=0; i<sz-1; i++)//控制比较的趟数
{
for(j=0; j<sz-1-i; j++)//控制比较的次数
{
if(arr[j]>arr[j+1])
{
int tmp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
}
}
}
}
int main()
{
int arr[]={6,5,4,3,2,1};
int i=0;
int sz=sizeof(arr)/sizeof(arr[0]);
bubble_sort(arr,sz);
for(i=0; i<sz; i++)
{
printf("%d ",arr[i]);
}
printf("\n");
system("pause");
return 0;
}
运行结果:
的确,达到了我们排序的结果,但是,殊不知我们做了很多不必要的工作,下面用一个例子来说明这个问题。
下面我们就来看看优化后的代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> void bubble_sort(int arr[],int sz) { int i=0; int j=0; int flag=0;//设置标志位控制多余的循环 for(i=0; i<sz-1; i++)//控制比较的趟数 { flag=0; for(j=0; j<sz-1-i; j++)//控制比较的次数 { if(arr[j]>arr[j+1])//如果arr[j]<=arr[j+1],则不进入后面的比较 { int tmp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=tmp; flag=1; } } if(flag==0) { break; } } } int main() { int arr[]={6,1,2,3,4,5}; int i=0; int sz=sizeof(arr)/sizeof(arr[0]); bubble_sort(arr,sz); for(i=0; i<sz; i++) { printf("%d ",arr[i]); } printf("\n"); system("pause"); return 0; }
运行结果:
通过上面的优化后,你能不能想到其他的优化方法呢?动脑筋思考一下,我是这样想的
代码实现:
程序运行结果:#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> void bubble_sort(int arr[],int sz) { int i=0; int j=0; int k=sz-1;//需要比较到的位置下标 int pos=0;//最后一次交换的位置下标 int flag=0;//优化不必要的循环,提高效率 for(i=0; i<sz-1; i++)//控制比较的趟数 { flag=0; for(j=0; j<k; j++)//控制比较的次数 { if(arr[j]>arr[j+1]) { int tmp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=tmp; flag=1; pos=j; } } if(flag==0) { break; } k=pos; } } int main() { int arr[]={1,2,3,6,5,4,7,8,9}; int i=0; int sz=sizeof(arr)/sizeof(arr[0]); bubble_sort(arr,sz); for(i=0; i<sz; i++) { printf("%d ",arr[i]); } printf("\n"); system("pause"); return 0; }
以上就是我对冒泡排序浅显的理解,如果你有其他优化方法,可以告诉我哦,
本人邮箱:2460804487@qq.com
2.直接插入排序
插入排序的基本思想:将需要排序的元素分为两部分,第一部分默认已经是有序序列(第一次分割时这部分仅为第一个元素),第二部分依次向后循环每个元素,将循环到的元素一个一个插入到第一部分的适合位置,当第二部分的所有元素循环完毕时,算法结束,此时排序成功!
插入代码:
结果:#include<stdio.h> #include<stdlib.h> void insert_sort(int arr[],int sz) { int i=0;//控制需要插入的元素arr[i] int j=0;//找出第一个比插入元素小的数arr[j] int k=0;//为插入做准备 int tmp=0;//保存需要插入的元素 for(i=1; i<sz; i++)//决定插哪个元素 { tmp=arr[i];//将arr[i]的值保存起来 for(j=i-1; j>=0; j--)//决定怎么插 { if(arr[j]<=tmp)//找到第一个比arr[i]小的数 { break; } } for(k=i-1; k>j; k--)//将需要插入的位置以后的元素向后移,为插入元素留出空位 { arr[k+1]=arr[k]; } arr[j+1]=tmp;//将需要插入的元素插入相应位置 } } int main() { int arr[]={6,5,4,3,2,1}; int i=0; int sz=sizeof(arr)/sizeof(arr[0]); insert_sort(arr,sz); for(i=0; i<sz; i++) { printf("%d ",arr[i]); } printf("\n"); system("pause"); return 0; }
仔细斟酌一下,可以发现里面的两层循环可以合二为一。
运行结果:#include<stdio.h> #include<stdlib.h> void insert_sort(int arr[],int sz) { int i=0; int j=0; int tmp=0; for(i=1; i<sz; i++) { tmp=arr[i]; for(j=i-1; (j>=0)&&(arr[j]>tmp); j--) { arr[j+1]=arr[j]; } arr[j+1]=tmp; } } int main() { int arr[]={6,5,4,3,2,1}; int i=0; int sz=sizeof(arr)/sizeof(arr[0]); insert_sort(arr,sz); for(i=0; i<sz; i++) { printf("%d ",arr[i]); } printf("\n"); system("pause"); return 0; }
3.选择排序基本思想:与插入排序一样,选择排序也是讲排序数组分为两部分,不同之处在于比较时总是拿第二部分的最小元素和第一部分的最后一个元素进行比较交换。
代码:
运行结果:#include<stdio.h> #include<stdlib.h> void choose_sort(int arr[],int sz) { int i=0;//控制假定有序的部分 int j=0;//找出无序部分的最小元素 int min=0;//无序部分的最小元素的下标 for(i=0; i<sz; i++) { min=i; for(j=i+1; j<sz; j++) { if(arr[j]<arr[min]) { int tmp=arr[j]; arr[j]=arr[min]; arr[min]=tmp; } } } } int main() { int arr[]={6,5,4,3,2,1}; int i=0; int sz=sizeof(arr)/sizeof(arr[0]); choose_sort(arr,sz); for(i=0; i<sz; i++) { printf("%d ",arr[i]); } printf("\n"); system("pause"); return 0; }
到这里,这三种算法的思想应该清楚了,永远记住一句话:算法是程序的灵魂!!!