数据结构笔记——第八章 排序技术

本文详细介绍了多种排序算法,包括插入排序(直接插入排序、希尔排序)、交换排序(起泡排序、快速排序)、选择排序(简单选择排序、堆排序)以及归并排序等。通过具体实例和算法实现代码,帮助读者理解各种排序算法的工作原理及其性能特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

8.1   概述

8.1.1   排序的基本概念

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

排序: 将一个记录的任意序列重新排列成一个按关键码有序的序列。

排序算法的稳定性:在原序列中,ki=kj,且ri在rj之前,在排序后的序列中,ri仍在rj之前,为排序算法稳定性;否则称为不稳定。

排序分类:插入、交换、选择、归并。

8.1.2  排序算法的性能

通常需要进行以下两种操作:1)比较,关键码之间的比较;2)移动,记录从一个位置移动到另一个位置

8.2   插入排序

主要思想:每次将一个待排序的记录按其关键码的大小插入到一个已经排好序的有序序列中,直到全部记录排好序。

8.2.1  直接插入排序

  基本思想:依次将待排序序列中的每一个记录插入到一个已排好序的序列中,直到全部记录都排好。

过程示例:

直接插入排序算法InsertSort

void InsertSort(int r[],int n)

{

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

           {

                          r[0]=r[i];

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

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

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

          }

}

8.2.2  希尔排序

  是对直接插入排序的一种改进,着眼点:1)若待排序记录按关键码基本有序,直接插入排序的效率很高;2)由于直接插入排序算法简单,则在待排序记录个数较少时效率也很高。

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

希尔排序算法ShellSort

void ShellSort(int r[],int n)

{

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

          {

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

              {

                     r[0]=r[i];

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

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

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

             }

       }

}

希尔排序的时间性能约为O(n^1.3)

8.3   交换排序

基本思想:在待排序序列中选两个记录,将他们的关键码进行比较,如果反序则交换他们的位置。

8.3.1  起泡排序

基本思想:两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止。

起泡排序算法BubbleSort

void BubbleSort(int r[],int n)

{

             int exchange=n,bound=n;

            while(exchang!=0)

             {

                    bound=exchange;exchange=0;

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

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

                  {

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

                              exchange=j;

                 }

           }

}

其执行时间取决于排序的趟数,时间复杂度为O(n^2)。

8.3.2  快速排序

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

基本思想:首先选一个轴值,将待排序记录划分成独立的两部分,左侧记录的关键码均小于或等于轴值,右侧记录的关键码均大于或等于轴值,然后分别对这两部分重复上述过程。

快速排序一次划分算法Partition

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

{

          int i=first;j=end;

          while(i<j)

         {

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

              if(i<j)

              {

                       r[0]=r[i];r[i]=r[j];r[j]=r[0];

                       i++;

               }

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

             if(i<j)

            {

                   r[0]=r[i];r[i]=r[j];r[j]=r[0];

                  j--;

            }

       }

        return i;

}

快速排序算法 QuickSort

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

{

       if(first<end)

       {

               int pivot=Partition(r,first,end);

               QuickSort(r,first,pivot-1);

              QuickSort(r,pivot+1,end);

       }

}

 8.4  选择排序

主要思想:每趟排序在当前待排序序列中选出关键码最小的记录,添加到有序序列中。

特点:记录移动的次数较少。

8.4.1   简单选择排序

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

简单选择排序算法Selectsort

void SelectSort(int r[],int n)

{

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

             {

                      int index=i;

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

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

                     if(index!=i)

                      {

                                r[0]=r[i];r[i]=r[index];r[index]=r[0];

                     }

           }

}

8.4.2  堆排序

对简单选择排序的改进,着眼点:如何减少关键码的比较次数。

1   堆的定义

堆是具有下列性质的完全二叉树:

1)每个节点的值都小于或等于其左右孩子结点的值(小根堆)

2)或每个结点的值都大于或等于其左右孩子结点的值(大根堆)

筛选法调整堆的算法Sift

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

{

                 int i=k;j=2*i;

                while(j<=m)

                 {

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

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

                       else

                      {

                            r[0]=r[i];r[i]=r[j];r[j]=r[0];

                           i =j;j=2*i;

                     }

            }

}

2    堆排序

堆排序算法HeapSort

void HeapSort(int r[],int n)

{

              int i=0;

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

             Sift(r,i,n);

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

           {

                     r[0]=r[1];r[1]=r[n-i+1];r[n-i+1]=r[0];

                     Sift(r,1,n-i);

           }

}

 8.5  归并排序

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

一次归并算法Merge

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

{

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

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

       {

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

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

        }

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

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

        else    while(j<=t)

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

}

一趟归并排序算法 MergePass

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

{

         i=1;

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

         {

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

                i+=2*h;

           }

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

         else   for(k=i;k<=n;k++)

                    r1[k]=r[k];

}

归并排序非递归算法MergeSort1

voidMergeSort1(int r[ ],int r1[ ],int n)

{

        h=1;

        while(h<n)

        {

               MergePass(r,r1,n,h);

               h=2*h;

               MergePass(r1,r,n,h);

                h=2*h;

          }

}

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

      归并排序的递归算法MergeSort2

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

{

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

             else

            {

                       m=(s+t)/2;

                      Mergesort2(r,r1,s,m);

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

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

            }

}

本章总结:

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值