冒泡排序和快速排序(C语言实现)
冒泡排序
冒泡排序的原理是:从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个。这个数就会从序列的最右边冒出来。
以从大到小排序为例,第一轮比较后,所有数中最小的那个数就会浮到最右边;第二轮比较后,所有数中第二小的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从大到小排序。
例如:5,2,3,4,1(从大到小排列)
第一轮:
(1)第一次:5与2 比较5>2就不用交换,此时的顺序为 5,2,4,3,1
(2)第二次 :2与3 比较2<3,此时交换2和3的位置,交换后顺序为 5,3,2,4,1
(3)第三次 :2与4比较2<4,此时交换2和4的位置,交换后顺序为 5,3,4,2,1
(4)第四次 :2与1比较2>1,此时位置不变。
第二轮:
(1)第一次 :5与3比较5>3,不用交换,此时顺序为 5,3,4,2,1
(2)第一次 :3与4比较3<4,交换3与4的位置,此时顺序为 5,4,3,2,1
(3)第三次 :3与2比较3>2,不用交换位置,此时顺序为 5,4,3,2,1
因为最后一个数在第一轮比较后已经是最小的数了,所以不用与已经排好序的数比较(此时只有最后一个数是已经拍好序的)。
第三轮:
(1)第一次 :5与4比较5>4,不用交换位置,此时顺序为 5,4,3,2,1
(2)第二次 :4与3比较4>3,不用交换位置,此时顺序为 5,4,3,2,1
因为最后一个数在第一轮比较后已经是最小的数了,所以不用与已经排好序的数比较(此时最后两个个数是已经拍好序的)。
在本次循环发现所有的数都没有交换位置所以此时已经完成了排序,就可以跳出循环。
代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void BubbleSort(int a[],int n,int *b){ //定义冒泡排序的函数:参数整形数组a[],数组长度n,记录比较轮数的整形指针
int i;//比较的次数
int j;//每轮比较的轮数
int temp;//交换数据时用于存放中间数据
int flag;//标志,用于记录本轮排序是否交换了数据
for(i=0; i< n-1;i++){//比较n-1轮
flag=0; //每轮比较前将标志置为0,表示为交换
for(j=0;j<n-1-i;j++){//没比较一轮就可以至少将一个数据放到正确的位置
//所以第i轮比较时只用比较n-1-i次
if(a[j]<a[j+1]){//判断j号数据是否小于j+1号数据
temp=a[j]; //若if中条件为真,进行数据交换
a[j]=a[j+1];
a[j+1]=temp;
flag=1; //交换数据后将交换数据的标志置为1
}
}
*b=*b+1; //每轮比较后比较的轮数加1
if(flag==0)//每轮比较完成后判断次轮是否交换过数据
return;//若没有交换数据,说明排序完成,退出函数
}
}
void display(int a[],int n){//定义输出数组数据的函数:参数(整形数组a[],数组长度n)
int i;
for(i=0;i<n;i++){
printf("%d\t",a[i]);
if((i+1)%5==0){
printf("\n\t");
}
}
printf("\n");
}
int main(int argc, char *argv[]) {
int count=0;
int a[]={5,2,6,15,12,18,3,66,19,20,23};
printf("排序前:");
display(a,sizeof(a)/sizeof(a[0]));//a[0]是int型, 占4字节, 所以总的字节数除以4等于元素的个数
BubbleSort(a,sizeof(a)/sizeof(a[0]),&count);
printf("排序后:");
display(a,sizeof(a)/sizeof(a[0]));
printf("共进行了%d循环",count);
return 0;
}
执行结果
快速排序
基本思想:
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
假设一开始序列a[i]是:5,3,7,6,4,1,0,2,9,10,8。
此时,key=5,low=1,high=11,从后往前找,第一个比5小的数是[8]=2,因此序列为:2,3,7,6,4,1,0,5,9,10,8。
此时low=1,high=8,从前往后找,第一个比5大的数是a[3]=7,因此序列为:2,3,5,6,4,1,0,7,9,10,8。
此时,low=3,high=8,从第8位往前找,第一个比5小的数是x[7]=0,因此:2,3,0,6,4,1,5,7,9,10,8。
此时,low=3,high=7,从第3位往后找,第一个比5大的数是a[4]=6,因此:2,3,0,5,4,1,6,7,9,10,8。
此时,low=4,high=7,从第7位往前找,第一个比5小的数是a[6]=1,因此:2,3,0,1,4,5,6,7,9,10,8。
此时,low=4,high=6,从第4位往后找,直到第6位才有比5大的数,这时,low=high=6,key成为一条分界线,它之前的数都比它小,之后的数都比它大,对于前后两部分数,可以采用同样的方法来排序.
代码实现:
#include <stdio.h>
#include <stdlib.h>
int Partition(int a[],int low ,int high){
int pivot=a[low];//选择一个标准数据
while(low<high){//执行循环直到high与low相遇是结束循环
while(low<high&&a[high]>=pivot)//从右往左找一直找到比基准数据小的数据跳出循环
high--;//没有找到比基准数据小的数据时就向前移动
a[low]=a[high];//找到比基准数据小时就将该数据赋给左边a[low];
while(low<high&&a[low]<=pivot)//从左往右找一直找到比基准数据大的数据跳出循环
low++;//没有找到比基准数据大的数据时就向后移动
a[high]=a[low];//找到比基准数据大时就将该数据赋给左边a[high];
}
a[low]=pivot;//跳出循环时low=high,此时low或者high就是基准数据的正确位置
return low;//返回基准数据的正确位置
}
void QuickSort(int a[],int low,int high){
if(low<high){//判断排序是否完成(当high=low说明排序完成)
int pivotpos=Partition(a,low,high);//记录上次排序完成时基准位置,作为分段的表准
QuickSort(a,low,pivotpos-1);//将上次排序后基准位置的左边数据进行排序
QuickSort(a,pivotpos+1,high);//对右边进行排序
}
}
void display(int a[],int n){//定义输出数组数据的函数:参数(整形数组a[],数组长度n)
int i;
for(i=0;i<n;i++){
printf("%d\t",a[i]);
if((i+1)%5==0){
printf("\n\t");
}
}
printf("\n");
}
int main(int argc, char *argv[]) {
int a[]={5,2,6,15,12,18,3,66,19,20,23};
printf("排序前:");
display(a,sizeof(a)/sizeof(a[0]));//a[0]是int型, 占4字节, 所以总的字节数除以4等于元素的个数
QuickSort(a,0,sizeof(a)/sizeof(a[0])-1);
printf("排序后:");
display(a,sizeof(a)/sizeof(a[0]));
}