还是以前老师上课总结的
//经典排序算法: 冒泡、选择、插入、希尔、快排、归并
#include<stdio.h>
#include<stdlib.h>
void swap0(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
//交换数组a[]中的第i和第j个元素
void swap(int *a, int i, int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
//输出数组中的元素
void println(int *a, int len){
for(int i=0;i<len-1;i++){
printf("%d ",a[i]);
}
printf("%d\n",a[len-1]);
}
void swapDemo(){
int m=-5, n=60;
swap0(&m,&n);
printf("%d %d\n", m,n);
int a[5] ={
1,3,5,7,9};
println(a,5);
//swap0( &a[0], &a[2] ); //法1
swap(a,0,2); //法2
println(a,5);
}
///1 冒泡/
//1.1 简单冒泡
void bubble(){
int a[10];
int len=10;
printf("请输入要排序的10个整数:");
freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
println(a,len);
//排序
for(int i=0;i<len-1; i++){
//趟数,所冒的泡数,总共需冒len-1个
//每趟冒一个泡: 每次都是从j=0开始,依次让j和j+1进行比较,若逆序则交换
for(int j=0; j<len-i-1; j++){
if(a[j]>a[j+1]){
swap(a,j,j+1);
}
}
}
println(a,len);
}
//1.2 优化的冒泡: 基本思想是当出现某一趟不存在逆序情况,则后面的趟数就不用进行了,因此此时序列已经有序
void bubble2(){
int a[10];
int len=10;
printf("请输入要排序的10个整数:");
freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
println(a,len);
//排序
for(int i=0;i<len-1; i++){
int isOk=1;//先假定已经有序
for(int j=0; j<len-i-1; j++){
if(a[j]>a[j+1]){
swap(a,j,j+1);
isOk=0; //有交换就是非"有序"
}
}
if(isOk)
break;
}
println(a,len);
}
//2 选择排序/
//2.1 排手机
void select0(){
int a[10];
int len=10;
printf("请输入要排序的10个整数:");
freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
println(a,len);
//排序
for(int i=0; i<len-1; i++){
//趟数,让第0个到第n-1个同学,每人分别进行一趟排序
//第i个同学排序时,从他后面那个同学开始,依次比较且发现逆序时交换
for(int j=i+1; j<len; j++ ){
if(a[i]>a[j]){
swap(a,i,j);
}
}
}
println(a,len);
}
//2.2 选择排序
void select(){
int a[10];
int len=10;
printf("请输入要排序的10个整数:");
freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
println(a,len);
//排序
for(int i=0; i<len-1; i++){
int k=i; //※用k记录第i趟当前子序列中最小数的位置
for(int j=i+1; j<len; j++ ){
if(a[k]>a[j]){
k=j;//※
}
}
//经过上面的循环,第k位置的元素一定是当前子序列中最小的元素
if(k!=i){
swap(a,k,i);
}//※
}
println(a,len);
}
/3 插入排序
//3.1 普通插入排序
void insertSort(){
int a[10];
int len=10;
printf("请输入要排序的10个整数:");
freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
println(a,len);
//排序
for(int i=0; i<len-1; i++){
//趟数=len-1, 依次把每个元素拿来插入到之前的有序子序列中(从第二个元素开始,到最后就行)
//每一趟插入第i+1个元素---待插入的元素, 此时前i个元素有序
int temp=a[i+1]; //先把待插入的元素备份到temp中
int j=i; //从i开始倒序(从后往前)进行遍历查找待插入位置
while(a[j]>temp){
//若a[j]大于temp则让a[j]往后挪一个位置
a[j+1]=a[j];
j--;
if(j<0){
break;
}
}
//经过上面的循环操作,j+1位置就是temp将要放置的。
//因为此时只有两种情况: temp>=a[j] 或 j=-1
a[j+1]= temp;
}
println(a,len);
}
//3.2 二分优化后的插入排序
void binaryInsertSort(){
int a[10];
int len=10;
printf("请输入要排序的10个整数:");
freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
println(a,len);
//排序
for(int i=0; i<len-1; i++){
int temp=a[i+1];
//1)用二分查找出temp将要放置的位置"high+1" 中的 high
int low = 0;
int high = i;
int mid;
while(low<=high){
mid = (low+high)>>1;
if(a[mid]>temp){
//左半区
high = mid-1;
}else{
//右半区
low = mid+1;
}
}
//经过上面循环的操作,找到temp将要放置的位置是:high+1
//2)把从high+1到i区间内的元素依次往后挪一个位置
for(int j=i; j>high; j--){
a[j+1]=a[j];
}
//3)让temp放置在high+1
a[high+1]= temp;
}
println(a,len);
}
4 希尔排序//
void shellSort(){
int a[10];
int len=10;
printf("请输入要排序的10个整数:");
//freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
println(a,len);
/*希尔排序: 是一种优化算法,用于优化越有序越有利的排序算法。
基本思想: 当序列非常无序时,gap很大(组内元素很少),此时排序比较快
(即使是n*n但n很少)。当gap越来越小时(组内元素越来越多),此时排序也比较快,因为越来越有序了。
*/
for(int gap=(len+1)/2; ; ){
//分组
//组内排序(使用越有序越有利的排序算法如插入排序法,此处为方便大家理解shell算法,我们用冒泡排序
for(int i=0; i<len-gap; i++){
for(int j=i; j<len-gap; j+=gap ){
if(a[j]>a[j+gap]){
swap(a,j,j+gap);
}
}
}
if(gap>1){
gap = (gap+1)/2;
}else{
break;
}
}
println(a,len);
}
//5 快速排序
/*
划分: 把a[p....r]范围内的元素进行划分,返回j,实现的功能:
j为枢轴的位置,a[p...j-1]为左半区(小区),a[j+1...r]为右半区(大区)
*/
int partition(int a[], int p, int r){
int i=p; //用于左侧遍历的游标-->找一个大于枢轴的数
int j=r+1; //用于右侧遍历的游标-->找一个小于枢轴的数
int x=a[p]; //把枢轴备份到x中
while(1){
//用i遍历,在左侧找一个大于枢轴的数
while(a[++i]<x && i<r);
//用j遍历,在右侧找一个小于枢轴的数
while(a[--j]>x);
if(i>=j){
break;
}
//把i和j位置的元素交换一下
swap(a,i,j);
}
//把枢轴(目前是p位置)交换到中间位置(j)
swap(a,p,j);
return j;//枢轴的位置
}
//把划分方法partition()优化一下,随机选择一个元素做为枢轴, 注意要导头文件:#include<stdlib.h>
int partition2(int a[], int p, int r){
/只是这几行是优化代码
srand( time(0) ); //用当前时间做种子,
int rnd = rand()%(r-p);
swap(a,p,p+rnd);
以下是原partition()中的代码///
int i=p; //用于左侧遍历的游标-->找一个大于枢轴的数
int j=r+1; //用于右侧遍历的游标-->找一个小于枢轴的数
int x=a[p]; //把枢轴备份到x中
while(1){
//用i遍历,在左侧找一个大于枢轴的数
while(a[++i]<x && i<r);
//用j遍历,在右侧找一个小于枢轴的数
while(a[--j]>x);
if(i>=j){
break;
}
//把i和j位置的元素交换一下
swap(a,i,j);
}
//把枢轴(目前是p位置)交换到中间位置(j)
swap(a,p,j);
return j;//枢轴的位置
}
void testPartition(){
int a[10];
int len=10;
printf("请输入要排序的10个整数:");
freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
partition(a,0,len-1);
println(a,len);
}
/*启发一下
void quickSort(){
int a[13] = {21,3,2,0,25, 49,25,16,8,23, 45,-3,4};
//划分一次
int q = partition(a,0,len-1);
int q2=partition(a,0,q-1);
int q3=partition(a,q+1,len-1);
int q21 = partition(a,0,q2-1);
int q22 = partition(a,q2+1,q-1);
int q31 = partition(a,0,q3-1);
int q32 = partition(a,q3+1,len-1);
//依此类推...
}
*/
void quickSort(int a[], int p, int r){
if(p<r){
//至少要有两个元素才划分
//划分, 结果: 左半区a[0,q-1], 枢轴a[q], 右半区a[q+1,r]
//int q = partition(a,p,r);
int q = partition2(a,p,r);
quickSort(a,p,q-1);
quickSort(a,q+1,r);
}
}
void testQuickSort(){
int a[50];
int len=50;
printf("请输入要排序的50个整数:");
freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
quickSort(a,0,len-1);
println(a,len);
}
6 归并排序///
//归并方法:把两个有序子序列合并成一个有序序列
void merge(int a[], int b[], int left, int mid, int right){
//该方法的具体功能: 把左子序列a[left,mid] 和 右子序列a[mid+1,right]归并到b[left,right]
int p=left; //遍历左子序列的游标
int r=mid+1; //遍历右子序列的游标
int k=left; //归并结果序列的游标---当前归并元素在结果集中的放置位置
while( p<=mid && r<=right){
if(a[p]<a[r]){
b[k++] = a[p++];
}else{
b[k++] = a[r++];
}
}
//经过上面的循环,一定有一个子序列已经归并完成。只时只要把没归并完的那个子序列剩下的元素直接照搬到结果集中
if(p>mid){
//左子序列归并完,照搬右子序列
for(int i=r;i<=right;i++){
b[k++] = a[i];
}
}else{
//右子序列归并完,照搬左子序列
for(int i=p;i<=mid;i++){
b[k++] = a[i];
}
}
}
void mergeSort(int a[], int left, int right){
if(left<right){
//至少2个元素
//先分解
int mid = (left+right)/2;
mergeSort(a,left,mid);
mergeSort(a,mid+1,right);
//再归并
int b[100];
merge(a,b,left,mid,right);
//把辅助序列b中的数据拷回到a中
for(int i=left;i<=right;i++){
a[i]=b[i];
}
}
}
void testMergeSort(){
int a[10];
int len=10;
printf("请输入要排序的10个整数:");
freopen("din.txt","r",stdin);
for(int i=0;i<len;i++){
scanf("%d",&a[i]);
}
println(a,len);
mergeSort(a,0,len-1);
println(a,len);
}
int main(){
//swapDemo();
//bubble();
//bubble2();
//select0();
//select();
//insertSort();
//binaryInsertSort();
//shellSort();
//testPartition();
testQuickSort();
//testMergeSort();
return 0;
}