第八章 排序技术



8 排序技术

8.1 概述

在排序问题中,通常将数据元素成为记录。

若待排序序列中的记录已按关键码排好序,称此记录序列为正序;若待排序序列中记录的排列顺序与排好序的顺序正好相反,称此记录序列为逆序或反序。

排序的分类

内排序是指在排序的整个过程中,待排序的所有记录全部被放在内存中;外排序是指由于待排序的记录个数太多,不能同时放置在内存,而需要将一部分记录放置在内存,另一部分记录放置在外存。

可以将平排序方法分为基于比较的排序和不基于比较的排序。

8.2插入排序

8.2.1 直接插入排序

直接插入排序是插入排序中最简单的排序方法,类似于玩纸牌是整理手中纸牌的过程。

直接插入排序算法InsertSort

void InsertSort{int r[],int n}

{

       for(i=2;i<=n;i++)

       {

              r[0]=r[i];

              for(j=i-1;r[0]<r[j];j--)

                     r[j+1]=r[j];

              r[j+1]=r[0];

       }

}

8.2.2 希尔排序

希尔排序的基本思想是:先将整个待排序记录序列分割成若干个子序列,在子序列内分别进行直接插入排序,待整个序列基本有序时,在对全体记录进行一次直接插入排序。

希尔排序算法ShellSort

void ShellSort(int r[],int n)

{

       for(d=n/2;d>=1;d=d/2)

       {

              for(i=d+1:i<=n;i++)

              {

                     r[0]=r[i];

                     for(j=i-d;j>0&&r[0]<r[j];j=j-d)

                            r[j+d]=r[0];

              }

       }

}

8.3 交换排序

8.3.1 起泡排序

起泡排序是交换排序中最简单的排序方法,其基本思想是两辆比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止。

起泡排序算法BubbleSort

void BubbleSort(intr[],int n)

{

    exchange=n;

    while (exchange!=0)

    {

        bound=exchange;exchange=0;

        for(j=1;j<bound;j++)

            if(r[j]>r[j+1]){

                r[j]←→r[j+1];

                exchange=j;

            }

    }

}

8.3.2 快速排序

快速排序是对起泡排序的一种改进,改进的着眼点是:在起泡排序中,记录的比较和移动是在相邻位置进行的,记录每次交换只能后移一个位置,因而总的比较次数和移动次数较多

选择轴值有多种方法,最简单的方法是选取第一个记录的关键码,还可以选取中间记录的关键码,或者在每次划分之前比较待排序序列的第一个记录,最后一个记录和中间记录的关键码,选取居中的关键码作为轴值并调换到第一个记录的位置。

一次划分的过程为

1 初始化

2 右侧扫描过程

3左侧扫描过程

4 重复2 3 步,直到ij指向同一位置,即轴值记录的最终的位置。

快速排序一次划分算法Partition

int Partition(intr[],int first,int end)

{

    i=first;j=end;

    while(i<j)

    {

        while(i<j&&r[i]<=r[j])j--;

        if(i<j){

            r[i]←→r[j];

            i++;

        }

        while(i<j&&r[i]<=r[j])i++;

        if(i<j){

            r[j]←→r[i];

            j--;

        }

    }

    return i;

}

快速排序算法QuickSort

void QuickSort(intr[],int first,int end)

{

    if(first<end){

        pivot=Patition(r,first,end);

        QuickSort(r,first,pivot-1);

        QuickSort(r,pivot+1,end);

    }

}

8.4 选择排序

选择排序是一类借助“选择”进行排序的方法,其主要思想是:每趟排序在当前待排序序列中选出关键码最小的记录,添加到有序序列中。选择排序的特点是记录移动的次数较少。

8.4.1 简单选择排序

简单选择排序是选择排序中最简单的排序方法,其基本思想是:第i趟排序在待排序序列r[i]~r[n](1in-1)中选取关键码最小的记录,并和第i个记录交换作为有序序列的第i个记录。

简单选择排序算法SelectSort

void SelectSort(int r[],int n)

{

       for(i=1;i<n;i++)

       {

              index=i;

              for(j=i+1;j<=n;j++)

                     if(r[j]<r[index])index=j;

                     if(index!=i)r[i]←→r[index];

       }

}

8.4.2 堆排序

堆排序是简单选择排序的一种改进,改进的着眼点是:如何减少关键码的比较次数。堆排序再选出最小关键码的同时,也找出较小关键码,减少了在后面等选择中的比较次数,从而提高了整个排序的效率。

1、 堆的定义

堆是具有下列性质的完全二叉树:每个结点的值都小于或等于其左右孩子堆点的值(称为小根堆);或者每个结点的值都大于或等于其左右孩子堆点的值(称为大根堆)

从堆的定义可以看出,一个完全二叉树如果是堆,则根节点(称为堆顶)一定是当前堆中所有结点中的最大者或最小者。

筛选法调整堆的算法Sift

void Sift(int r[],int k,int m)

{

       i=k;j=2*1;

       while(j<=m)

       {

              if(j<m&&r[j]<r[j+1])j++;

              if(r[i]>r[j])break;

              else{

                     r[i]←→r[j];

                     i=j;j=2*i;

              }

       }

}

2、 堆排序

堆排序是利用堆的特性进行排序的方法,其基本思想是:首先将待排序的记录序列构造成一个堆,此时,选出了堆中所有记录的最大者即堆顶记录。然后将堆顶记录移走,并将剩余的记录再调整成堆,这样又找出了次大的记录。以此类推,直到堆中只有一个记录为止

堆排序算法HearSort

void HeapSort(int r[],int n)

{

       for(i=n/2;i>=1;i--)

              Sift(r,i,n);

       for(i=1;i<n;i++)

       {

              r[1]←→r[n-i+1];

              Sift(r,i,n-i);

       }

}

8.5 归并排序

8.5.1 二路归并排序的非递归实现。

具体的排序过程是:将具有n个待排序的记录序列看成是n个长度为1的有序序列,然后进行两辆归并,得到[n/2]个长度为2(最后一个有序序列的长度可能是1)的有序序列,再进行两辆归并,得到[n/4]个长度为4的有序序列(最后一个有序序列的长度可能小于4),……直至得到一个长度为n的有序序列。

一次病归算法 Merge

void Merge(int r[],int r1[],int s,int m,intt)

{

       i=s;j=m+1;k=s;

       while(i<=m&&j<=t)

       {

              if(r[i]<=r[j])r1[k++]=r[i++];

              elser1[k++]=r[j++];

       }

       if(i<=m)while(i<=m0

              r1[k++]=r[i++];

       elsewhile (j<=t)

              r1[k++]=r[j++];

}

一趟归并排序算法MergePass

void MergePass(int r[],int r1[],int n,inth)

{

       i=1;

       while(i<=n-2h+1)

       {

              Merge(r,r1,i,i+h-1,i+2*h-1);

              i+=2*h;

       }

       if(i<n-h+1)Merge(r,r1,i,i+h-1,n);

       elsefor(k=i;k<=n;k++)

              r1[k]=r[k];

}

归并排序非递归算法MergeSort

void MergeSort1(int r[],int r1[],int n)

{

       h=1;

       while(h<n)

       {

              MergeSort(r,r1,n,h);

              h=2*h;

              MergePass(r1,r,n,h);

              h=2*h;

       }

}

8.5.2 二路归并排序的递归实现

二路并归排序方法也可以用递归的形式描述,即首先将待排序的记录序列分为两个相等的子序列,并分别将这两个子序列用并归方法进行排序,然后调用一次并归算法Merge,再将这两个有序子序列合并成一个含有全部记录的有序序列。

归并排序的递归算法MergeSort2

void MergeSort2(int r[],int r1[],int s,intt)

{

       if(s==t)r1[s]=r[s];

       else{

              m=(s+t)/2;

              Mergesort2(r,r1,s,m);

              Mergesort2(r,ri,m+1,t);

              Merge(r1,r,s,m,t);

       }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值