算法第4版本-排序复习01-20200602

选择排序\插入排序\希尔排序

  • 选择排序
    首先找到数据序列中最小(最大)的那个元素,其次将它和数组的第一个元素交换位置,然后在剩下的元素中找到最小的元素,将它和序列中第二个元素交换位置,循环执行,直至到达序列的最后一个元素位置.之所以叫做选择排序,是因为在每一轮排序中都在选择最小(最大)的那个元素.
    选择排序的运行时间和输入无关,当前的一轮排序并不能为下一轮排序提供排序信息,这也导致当输入序列是一个有序序列的时候,选择排序依然会老老实实的经历Length轮排序.在选择排序过程中,数据移动的次数为Length次,每一轮排序选出一个,然后交换.
typedef struct {
    int r[max];//被排序序列
    int length;//序列长度
}Sort_Alg;

void Select_Alg(Sort_Alg *L){
    int min;//or max
    for (int i = 0; i < L->length; ++i) {
        min=i;
        for (int j = i+1; j < L->length; ++j) {
            if(L->r[j]<L->r[min]){
                min=j;
            }
        }
        if(min!=i){
            exchangeIndex(L,min,i);//交换序列中的min和i索引的位置
        }
    }
}
  • 插入排序
    是将一个数据插入到一个已经排好序的序列中,在未知序列元素的情况下,只能将数组的第一个元素作为已经排好序的有序序列
    从序列的第二个数据开始,将其与第一个数据进行比较,如果比第一个大,就放着不管,比第一个小就将第一个数据往后移一步,将第二个插入到第一个数据中去.
    然后读取序列的第三个说,首先将其与第二个数据比较,如果比第二个大,就放着不管,比第二个小,就将第二个数据往后移一步,将第三个放在第二个索引位置,然后再与第一个数据进行比较,如果比第一个大,就放着不管,结束插入,如果比第一个小,就将第一个数据往后移一步,此时第三个数据就位于第一个索引位置.如此往复即可.
    需要明确的是,插入排序中当前插入数据的左侧序列始终是有序的,执行第N轮排序时,数据间比较的最大次数是N-1次比较和N-1次数据交换.
void Insert_Alg(Sort_Alg *L){
	//排序外循环从索引1即第二个元素开始,到最后一个索引结束插入
    for (int i = 1; i < L->length; ++i) {
    	//排序内循环从当前索引开始"""向前"""进行数据比较
        for (int j = i; j > 0; --j) {
            if(L->r[j]<L->r[j-1]){
            	//如果当前数据比前一个数据小,就交换索引
            	//其余情况无需操作
                exchangeIndex(L,j,j-1);
            }
        }
    }
}
  • 希尔排序
    高级版插入排序
    整个排序的过程是使序列中的元素保持H间隔有序,比如:
    序列[1,4,7,2,6,9,3,7,12]
    间隔H=2有序,分别是
    [1,2,3]
    [4,6,7]
    [7,9,12].
    从序列输入开始,使用Length/2(或者Length/3)作为间隔,对元素进行排序,一轮排序过后,将间隔再次除2(或除3),直至到间隔为1.
    希尔排序的高效性是体现在,排序前对序列进行了分组,对每一组子序列进行排序后,子序列均表现为部分有序,满足插入排序的需求.
    希尔排序的性能取决于间隔H与每个H之间的关系,(…有点儿深奥,我靠死记硬背的,间隔H-两层循环-内外递减-完事儿…)
void ShellSort_Alg(Sort_Alg *L){
    int N=L->length;
    int h=1;
    //该while是为了寻找最佳的最大初始间隔
    while(h<N/2){
        h=2*h;
    }
    while (h>=1){
        //外循环从h索引开始,直至序列末尾
        for (int i = h; i < N; ++i) {
        	//内循环索引也是从h开始,以h为间隔往前退,直至j<h停止
            for (int j = i; j >= h; j-=h) {
                if(L->r[j]<L->r[j-h]){
                	//如果当前索引j的数据比前间隔h索引的元素小,就将其索引交换
                    exchangeIndex(L,j,j-h);
                }
            }
        }
        //递减间隔,直至h=1,完成排序
        h/=2;
    }
}
  • 归并排序
    归并排序的流程更像是将排序的工作分成两部分,然后再将该两部分再次分别分为两部分,直至触底,这里的触底指的是分到了只有一个元素的时候,肯定是一个有序序列,所以就触底了,然后再返回这个分半的上级分半.高级的说法叫做"分治".
    这里进行分治之后,就需要进行归并的操作了,例如已知两序列有序序列A和B,要将这两个序列归并成一个有序序列,即分别从两序列头索引开始,先进行比较,如果A序列的A[0]小于B序列的B[0],此时将A[0]放入大序列,A的索引自增1,B索引不变,然后将A[1]与B[0]进行比较,直至A和B两个序列抵达尾索引即完成归并.
    总得来说一共两步:
    拆拆拆…并并并…
//拆分
void MergeSort_Alg(Sort_Alg *L,int left,int right){
    if(right-left<1)
    	//如果分段后序列只有一个元素,则返回递归
        return;
    //如果仍然可以拆分,就继续
    int mid=(left+right)/2;//记录中间索引
    MergeSort_Alg(L,left,mid);//拆分前半段
    MergeSort_Alg(L,mid+1,right);//拆分后半段
    Merge_Alg(L,left,right);//合并------归并排序的关键
}
//归并
void Merge_Alg(Sort_Alg *L,int left,int right){
    int i=left,j=(left+right)/2+1,k=left,mid=(left+right)/2;
    int temp[L->length];//创建temp数组,暂存段内数据
    for (int l = left; l <= right; ++l) {
    	//进入归并函数,首先复制需要归并的两段数据
        temp[l]=L->r[l];
    }
    while(k<=right){
    //从段头left开始直至k递增到right
        if (i>mid){
        //如果前半段已经完成归并
        //持续放置后半段数据
            L->r[k]=temp[j];
            k++;j++;
        } else if (j>right){
        //如果后半段已经完成归并
        //持续放置前半段
            L->r[k]=temp[i];
            k++;i++;
        } else {
        //前后两段序列均未放置完毕,进行大小比较
        //改升序和降序就在这里改
            if (temp[i] < temp[j]) {
                L->r[k] = temp[i];
                k++;i++;
            } else {
                L->r[k] = temp[j];
                k++;j++;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值