基础笔记:排序算法(一)(选择、插入、冒泡)

排序任务目标假定:将含有n个乱序整数的数组排列为从小到大升序排列的整数数组


选择排序

选择排序:每次从待排序的序列里选一个最小数将其换到目标位置(也即此趟排序排到的位置,该位置之前的数已经都是排好的了)。

核心:选择待排序序列中的最小数(内层循环负责);交换最小数到目标位置(外层循环负责,如第 i 趟排序即将最小数交换到第 i 个位置)

#include<stdio.h>

void swap(int* a,int* b){ /* 交换两数的值 */
int tmp;
tmp=*a;
*a=*b;
*b=tmp;
}

void print_array(int* a, int start, int end){ /* 打印数组 */
int k;
for(k=start;k<=end;k++)
    printf("%d ",a[k]);
printf("\n");
}

void select_sort(int *a , int n){
    int i;
    int j;
    int min;
    for(i=0; i<n-1; i++){    /* 外层循环负责交换及交换次数(也即排列趟数),由于排列到最后剩下的最后一个数默认有序为最大值,所以总排序趟数为n-1次 */
        min=i;              /* 默认将待排序序列里的第一个标识为最小值 */
        for(j=i+1; j<n; j++){  /* 内层循环负责找到最小值,待排序序列是从i+1开始的,之前的数已排好序 */
            if(a[min]>a[j]){  /* 从待排序列中从第二个数开始依次与目前所标识的最小值比较 */
                min=j;       /* 若找到更小的数,则重新标识最小值 */
            }
        }
        if(min!=i)           /* min是否与初始值不同,不同说明找到更小值的标号,需要与当前位置 i 处的数进行交换 */
            swap(&a[i],&a[min]);

        /* 打印每趟排序的结果 */
        print_array(a,0,n-1);
    }
}

void main(){
int a[]={5,4,7,6,9,8,1,0,3,2};
int len=sizeof(a)/sizeof(a[0]);
select_sort(a,len);
}

/**
 * 0 4 7 6 9 8 1 5 3 2 
 * 0 1 7 6 9 8 4 5 3 2 
 * 0 1 2 6 9 8 4 5 3 7 
 * 0 1 2 3 9 8 4 5 6 7 
 * 0 1 2 3 4 8 9 5 6 7 
 * 0 1 2 3 4 5 9 8 6 7 
 * 0 1 2 3 4 5 6 8 9 7 
 * 0 1 2 3 4 5 6 7 9 8 
 * 0 1 2 3 4 5 6 7 8 9 
**/



插入排序

插入排序:每次将待排序序列里的第一个值插入到前面已排好的序列中的适当位置。
核心:1,外层循环负责选择待排序序列的第1个值用于后面插入;2,内层循环负责通过比较找到合适的插入位置,然后移动数组空出待插入位置将数字插入。

#include<stdio.h>
/* 插入排序:内层循环为 while 循环的版本*/

void print_array(int* a, int start, int end){ /* 打印数组 */
int k;
for(k=start;k<=end;k++)
    printf("%d ",a[k]);
printf("\n");
}

void insert_sort(int *a, int n){
int i;
int j;
int tmp;
for(i=1;i<n;i++){   /* 外层循环选择待插入的值并控制插入次数,以及将待插入值插入适当位置 */
    tmp=a[i];       /* tmp保存待插入的值*/
    j=i-1;          /* 从待排序序列的前一个数开始比较待插入值与前面序列数字的大小*/
    while(tmp<a[j]&&j>=0){    /* 内层循环负责找到比待插入值小的数的后面那个位置  */
        a[j+1]=a[j];   /* 比tmp 大的已排序序列要向后移*/
        j--;
    }
    a[j+1]=tmp; /* 将待插入值插入到适当位置 */
    /* 打印每次排序后的结果 */
    print_array(a,0,n-1);
 }
 }

void main(){
int a[]={5,4,7,6,9,8,1,0,3,2};
int n=sizeof(a)/sizeof(a[0]);
insert_sort(a,n);
}

/**
 * 4 5 7 6 9 8 1 0 3 2 
 * 4 5 7 6 9 8 1 0 3 2 
 * 4 5 6 7 9 8 1 0 3 2 
 * 4 5 6 7 9 8 1 0 3 2 
 * 4 5 6 7 8 9 1 0 3 2 
 * 1 4 5 6 7 8 9 0 3 2 
 * 0 1 4 5 6 7 8 9 3 2 
 * 0 1 3 4 5 6 7 8 9 2 
 * 0 1 2 3 4 5 6 7 8 9 
**/



冒泡排序

冒泡排序:每趟排序,都依次将待排序序列中相邻的两个记录进行比较和交换,这样每趟排序结束都会将最小(大)的数换到最前(后)面。
核心:没趟排序相邻两数比较和交换。

最简单的冒泡排序:

#include<stdio.h>
/* 最简单的冒泡排序 */

void swap(int* a,int* b){  /* 交换两数的值 */
int tmp;
tmp=*a;
*a=*b;
*b=tmp;
}

void print_array(int* a, int start, int end){ /* 打印数组 */
int k;
for(k=start;k<=end;k++)
    printf("%d ",a[k]);
printf("\n");
}

void bubble_sort(int *a, int n){
int i;
int j;
for(i=0;i<n-1;i++){   /* 外层循环负责控制排序趟数 */
    for(j=n-1;j>i;j--){ /* 内层循环负责依次比较相邻的两个数,并交换符合条件的相邻两数 */
        if(a[j]<a[j-1])  /* 将小数交换到前面,这样每趟比较过后最小的数都会交换到前面 */
            swap(&a[j],&a[j-1]);
    }
    /* 打印每趟排序后的结果 */
    print_array(a,0,n-1);
}
}

void main(){
int a[]={5,4,7,6,9,8,1,0,3,2};
int len=sizeof(a)/sizeof(a[0]);
bubble_sort(a,len);
}
/**
 * 0 5 4 7 6 9 8 1 2 3
 * 0 1 5 4 7 6 9 8 2 3
 * 0 1 2 5 4 7 6 9 8 3
 * 0 1 2 3 5 4 7 6 9 8
 * 0 1 2 3 4 5 6 7 8 9
 * 0 1 2 3 4 5 6 7 8 9
 * 0 1 2 3 4 5 6 7 8 9
 * 0 1 2 3 4 5 6 7 8 9
 * 0 1 2 3 4 5 6 7 8 9
**/

加标志位改进的冒泡排序

#include<stdio.h>
/* 加标志位进行改进的冒泡排序 */

void swap(int* a,int* b){  /* 交换两数的值 */
int tmp;
tmp=*a;
*a=*b;
*b=tmp;
}

void print_array(int* a, int start, int end){ /* 打印数组 */
int k;
for(k=start;k<=end;k++)
    printf("%d ",a[k]);
printf("\n");
}

void bubble_sort(int *a, int n){
int i;
int j;
int flag; /* flag 用于标识一趟排序中是否有相邻两数交换过位置,有为1,没有为0*/
for(i=0;i<n-1;i++){ /* 外层循环负责控制排序趟数 */
    flag=0 ;                 /* 默认本趟排序刚开始还未发生过相邻两数交换 */
    for(j=n-1;j>i;j--){
       if(a[j]<a[j-1]){
           swap(&a[j],&a[j-1]);
           flag=1 ;            /* 如果排序中发生了相邻两数交换就用flag=1进行标注 */
        }
    }
    if(flag==0)
        break;  /* 如果本趟排序没有相邻元素交换,说明序列已经排好序了,需要退出循环*/
    else      /* 如果发生交换,打印交换排序后的结果 */
        print_array(a,0,n-1);
}
}

void main(){
int a[]={5,4,7,6,9,8,1,0,3,2};
int len=sizeof(a)/sizeof(a[0]);
bubble_sort(a,len);
}

/**
 * 0 5 4 7 6 9 8 1 2 3 
 * 0 1 5 4 7 6 9 8 2 3 
 * 0 1 2 5 4 7 6 9 8 3 
 * 0 1 2 3 5 4 7 6 9 8 
 * 0 1 2 3 4 5 6 7 8 9 
**/

双向冒泡排序

#include<stdio.h>
/* 
双向冒泡排序:外部循环为 do...while 循环的版本
双向冒泡排序就是每趟排序时,对待排序序列,先正向比较和交换相邻两数将最大的数换到末尾,然后再反向依次比较和交换相邻两数,将最小的数排到首位。
因此其内层有两个循环,每个循环控制一个方向的排序。
*/

void swap(int* a,int* b){  /* 交换两数的值 */
int tmp;
tmp=*a;
*a=*b;
*b=tmp;
}

void print_array(int* a, int start, int end){ /* 打印数组 */
int k;
for(k=start;k<=end;k++)
    printf("%d ",a[k]);
printf("\n");
}

void bubble_sort(int *a, int n){
int left=0; 
int right=n-1;
int i;
int flag; /* flag 用于标识一趟排序中是否有相邻两数交换过位置,有为1,没有为0*/
do{ /* 外层循环负责控制排序趟数 */
    for(i=right;i>left;i--){    /* 该循环负责从后向前的方向,每趟排序将最小数换到前面,注意 i 的范围 */
       if(a[i]<a[i-1]){
           swap(&a[i],&a[i-1]);
           flag=i ;            /* 用flag=i记录最后一次发生交换的位置 */
        }
    }
    left=flag; /* left 记录从前向后方向的起始位置 */
    printf("left:%d ",left);
    for(i=left;i<right;i++){     /* 该循环负责从前向后的方向,每趟排序将最大数换到后面,注意 i 的范围 */
        if(a[i]>a[i+1]){
            swap(&a[i],&a[i+1]);
            flag=i;
        }
    }
    right=flag; /* right 记录从后向前方向的起始位置 */
    printf("right:%d    ",right);
    print_array(a,0,n-1);
}while(left<right);
}

void main(){
int a[]={5,4,7,6,9,8,1,0,3,2};
int len=sizeof(a)/sizeof(a[0]);
bubble_sort(a,len);
}

/**
left:1 right:8   0 4 5 6 7 8 1 2 3 9 
left:2 right:7   0 1 4 5 6 7 2 3 8 9 
left:3 right:6   0 1 2 4 5 6 3 7 8 9 
left:4 right:4   0 1 2 3 4 5 6 7 8 9 
**/

 后续 《基础笔记:排序算法(二)(归并、快速、希尔、堆)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值