C#从入门到精通(第4版)
上QQ阅读APP看书,第一时间看更新

7.5 数组排序算法

视频讲解:光盘\TM\lx\7\05数组排序算法.mp4

数组有很多常用的算法,本节将介绍常用的排序算法,包括冒泡排序法、直接插入排序法和选择排序法。

7.5.1 冒泡排序

冒泡排序方法以简洁的思想与实现方法而备受青睐,是广大初学者最先接触的一个排序算法。这种方法排序数组元素的过程总是小数往前放,大数往后放,类似水中气泡往上升的动作,所以称作冒泡排序。

1.基本思想

冒泡排序的基本思想是对比相邻的元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部。

2.算法示例

冒泡算法由双层循环实现,其中外层循环用于控制排序轮数,一般是要排序的数组长度减1次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序了。而内层循环主要用于对比数组中每个临近元素的大小,以确定是否交换位置,对比和交换次数以排序轮数而减少。例如,一个拥有6个元素的数组,在排序过程中每一次循环的排序过程和结果如图7.13所示。

图7.13 6个元素数组的排序过程

第一轮外层循环时把最大的元素值63移动到了最后面(相应的比63小的元素向前移动,类似气泡上升),第二轮外层循环不再对比最后一个元素值63,因为它已经确认为最大(不需要上升),应该放在最后,需要对比和移动的是其他剩余元素,这次将元素24移动到了63的前一个位置。其他循环将依此类推,继续完成排序任务。

3.算法实现

下面来介绍一下冒泡排序的具体用法。

【例7.19】创建一个控制台应用程序,使用冒泡法对数组中的元素从小到大进行排序。程序代码如下。(实例位置:光盘\TM\sl\7\9)

        static void Main(string[] args)
        {
          int[] arr=new int[]{63, 4, 24, 1, 3, 15};           //定义一个一维数组,并赋值
          //定义两个int类型的变量,分别用来表示数组下标和存储新的数组元素
          int j, temp;
          for (int i=0; i<arr.Length-1;i++)                  //根据数组下标的值遍历数组元素
          {
              j = i + 1;
              id:                                            //定义一个标识,以便从这里开始执行语句
              if (arr[i]>arr[j])                             //判断前后两个数的大小
              {
                  temp=arr[i];                               //将比较后大的元素赋值给定义的int变量
                  arr[i]=arr[j];                             //将后一个元素的值赋值给前一个元素
                  arr[j]=temp;                               //将int变量中存储的元素值赋值给后一个元素
                  goto id;                                   //返回标识,继续判断后面的元素
              }
              eIse
                  if (j<arr.Length-1)                        //判断是否执行到最后一个元素
                  {
                    j++;                                      //如果没有,则再往后判断
                    goto id;                                  //返回标识,继续判断后面的元素
                  }
          }
          foreach (int n in arr)                              //循环遍历排序后的数组元素并输出
              Console.Write(n + " ");
          Console.WriteLine();
      }

按Ctrl+F5键查看运行结果,如图7.14所示。

图7.14 冒泡法排序实例运行结果

注意 在对数组进行遍历时,要用当前数组的Length属性来获取数组的元素个数。

从实例的运行结果来看,数组中的元素已经按从小到大的顺序排序好了。冒泡排序的主要思想就是:把相邻两个元素进行比较,如满足一定条件则进行交换(如判断大小或日期前后等),每次循环就将最大(或最小)的元素排在最后,下一次循环是对数组中其他的元素进行类似操作。

7.5.2 直接插入排序

直接排序方法是一种常用的数组排序算法,是初学者应该掌握的。

1.基本思想

直接插入排序是一种最简单的排序方法,其基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表,然后再从剩下的关键字中选取下一个插入对象,反复执行直到整个序列有序。

2.算法示例

插入排序法实现时,将n个有序数存放在数组a中,要插入的数为x,首先确定x插在数组中的位置p,数组中p之后的元素都向后移一个位置,空出a(p),将x放入a(p)。这样即可实现插入后数列仍然有序。

举例:

    初始数组资源 【63 4 24 1 3 15】
    第一趟排序后 【4 63】 24 1 3 15
    第二趟排序后 【4 24 63】 1 3 15
    第三趟排序后 【1 4 24 63】 3 15
    第四趟排序后 【1 3 4 24 63】 15
    第五趟排序后 【1 3 4 15 24 63】
  
3.算法实现

下面来介绍一下直接插入排序的具体用法。

【例7.20】创建一个控制台应用程序,使用直接插入法对数组中的元素从小到大进行排序。程序代码如下。(实例位置:光盘\TM\sl\7\10)

        static void Main(string[] args)
        {
            int[] arr=new int[]{63, 4, 24, 1, 3, 15};           //定义一个一维数组,并赋值
            for (int i=0; i<arr.Length;++i)                     //循环访问数组中的元素
            {
              int temp=arr[i];                                  //定义一个int变量,并使用获得的数组元素值赋值
              int j=i;
              whiIe ((j>0)&&(arr[j-1]>temp))                    //判断数组中的元素是否大于获得的值
              {
                  arr[j]=arr[j-1];                              //如果是,则将后一个元素的值提前
                  --j;
              }
              arr[j]=temp;                                      //最后将int变量存储的值赋值给最后一个元素
            }
            Console.WriteLine("排序后结果为:");
            foreach (int n in arr)                              //循环访问排序后的数组元素并输出
              Console.Write("{0}", n + " ");
            Console.WriteLine();
        }

按Ctrl+F5键查看运行结果,如图7.15所示。

图7.15 直接插入法排序实例运行结果

闯关训练:使用希尔排序算法对一维数组“63, 4, 24, 1, 3, 15”进行排序。希尔排序又称“缩小增量排序”,其基本思想是,先将整个待排序的一组序列分割成为若干子序列,然后分别进行直接插入排序,待整个序列中的数“基本有序”时再对全体记录进行一次直接插入排序。

7.5.3 选择排序法

选择排序方法的排序速度要比冒泡排序快一些,也是常用的排序算法,是初学者应该掌握的。

1.基本思想

选择排序的基本思想是将指定排序位置与其他数组元素分别对比,如果满足条件就交换元素值,注意这里有别于冒泡排序,不是交换相邻元素,而是把满足条件的元素与指定的排序位置交换(如从第一个元素开始排序),这样排序好的位置逐渐扩大,最后整个数组都成为已排序好的格式。

这就好比有一个小学生,从包含数字1~10的乱序的数字堆中分别选择合适的数字,组成一个从1~10的排序,而这个学生首先从数字堆中选出1,放在第一位,然后选出2(注意这时数字堆中已经没有1了),放在第二位,依次类推,直到其找到数字9,放到8的后面,最后剩下10,就不用选择了,直接放到最后就可以了。

与冒泡排序相比,选择排序的交换次数要少很多,所以速度会快些。

2.算法示例

每一趟在n个记录中选取关键字最小的记录作为有序序列的第I个记录,并且令I为1~n-1,进行n-1趟选择操作。

例如:

    初始数组资源 【63 4 24 1 3 15】
    第一趟排序后【1】 4 24 63 3 15
    第二趟排序后【1 3】 24 63 4 15
    第三趟排序后【1 3 4】 63 24 15
    第四趟排序后【1 3 4 15】 24 63
    第五趟排序后【1 3 4 15 24】 63
  
3.算法实现

下面来介绍一下选择排序法的具体用法。

【例7.21】创建一个控制台应用程序,使用选择排序法对数组中的元素从小到大进行排序,程序代码如下。(实例位置:光盘\TM\sl\7\11)

        static void Main(string[] args)
        {
            int[] arr=new int[]{63, 4, 24, 1, 3, 15};           //定义一个一维数组,并赋值
            int min;                                            //定义一个int变量,用来存储数组下标
            for (int i=0; i<arr.Length-1; i++)                  //循环访问数组中的元素值(除最后一个)
            {
              min=i;                                            //为定义的数组下标赋值
              for (int j=i+1; j<arr.Length; j++)                //循环访问数组中的元素值(除第一个)
              {
                  if (arr[j]<arr[min])                          //判断相邻两个元素值的大小
                      min=j;
              }
              int t=arr[min];                                   //定义一个int变量,用来存储比较大的数组元素值
              arr[min]=arr[i];                                  //将小的数组元素值移动到前一位
              arr[i]=t;                                         //将int变量中存储的较大的数组元素值向后移
            }
            Console.WriteLine("排序后结果为:");
            foreach (int n in arr)                              //循环访问排序后的数组元素并输出
              Console.Write("{0}", n + " ");
            Console.WriteLine();
        }

按Ctrl+F5键查看运行结果,如图7.16所示。

图7.16 选择排序法实例运行结果