经典排序算法(一)

For study!

Posted by Winray on March 5, 2016
概述

排序是计算机程序设计中的一种重要操作,简单的说,可以使任意序列重新排列成一个按关键字有序的序列。

  • 好处:
    • 有序顺序可以采用查找效率较高的折半查找法
    • 有如建造数表(无论是二叉树还是B-树)的过程本身就是一个排序的过程
稳定与否
  • 若两个相等数,在排序前与排序后的顺序相同,则是稳定的排序,否则是不稳定的。
  • eg:

    假设:	 a = b
    稳定:	 a, b -->  a, b
    不稳定:  a, b -->  b, a
    
内(/外)部排序
  • 内部排序:指的是带排序的记录存放在计算机存储器中进行的排序过程
    • 插入排序
    • 交换排序
    • 选择排序
    • 归并排序
    • 计数排序
  • 外部排序:指的是带排序的记录数量很大,以致内存一次不能容纳全部记录,在排序过程中尚需对外存进行访问的排序过程。
两种基本操作
  • 比较两个关键字的大小
  • 将记录从一个位置移动至另外一个记录

排序算法

  • 下面正式介绍各种排序算法
  • 都是从小到大排序
  • 以整形为例
插入排序
  • 直接插入排序,是一种最简单的排序方法
  • 基本操作是将一个记录插入到已排好的有序表中从而得到一个新的、记录数增1的有序表。

    void insertSort(int test[], int len) {
          if (len < 2) return;
          for (int i = 1; i < len; i++) {
              int tmp = test[i], j;
              for (j = i; j > 0 && tmp < test[j-1]; j--) {
                  //把比插入元素大的元素后移 
                  test[j] = test[j-1];
              }
              //找打合适位置插入 
              test[j] = tmp;
          }
      }
    
希尔排序
  • 插入排序改进版
  • 改进:
    • 通过比较相距一定间隔的元素来工作;
    • 随着每一趟比较所用的距离随着算法的进行而减小;
    • 直到只比较相邻元素的最后一趟排序位置。
  • 为此,希尔排序有时也叫缩减增量排序。

    void shellSort(int test[], int len) {
      for (int gap = len/2; gap > 0; gap /= 2) {
          //选取步长 
          for (int i = gap; i < len; i++) {
              //以步长进行的选择排序 
              int tmp = test[i], j;
              for (j = i; j >= gap && tmp < test[j-gap]; j -= gap) {
                  test[j] = test[j-gap];
              }
              //找到合适位置插入 
              test[j] = tmp;
          }
      }
    }
    
冒泡排序
  • 每一轮都把这轮的最大放到最后的位置
  • 如:
    • 第一轮把最大的数字放到最后一位
    • 第二轮把最大的数字放到倒数第二位
    • 第三轮把最大的数字放到倒数第三位
    • 以此类推
    void bubbleSort(int test[], int len) {
      for (int i = 1; i < len; i++) {
          //每一轮都把这轮最大的数放到(‘len-i’位置)
          for (int j = 0; j < len-i; j++) {
              if (test[j] > test[j+1]) {
                  int tmp = test[j+1];
                  test[j+1] = test[j];
                  test[j] = tmp;			
              }
          }
      }
    }
    
选择排序
  • 类似冒泡排序
  • 但是交换次数减少,因为冒泡排序是通过每一次交换把数字替换,而选择排序是选出最小一位再交换,效果更好
  • 找到每一轮的最小元素,然后替换,直到最后排序完成
  • 如:
    • 第一轮把最小的数字放到第一位
    • 第二轮把最小的数字放到第二位
    • 第三轮把最小的数字放到第三位
    • 以此类推。
    void selectSort(int test[], int len) {
      for (int i = 0; i < len; ++i) {
          //记录当前为最小元素 
          int index = i;
          //找到最小元素 
          for (int j = i+1; j < len; ++j) {
              if (test[j] < test[index]) {
                  index = j;
              }
          }
          //如果找到的最小元素比记录的最小元素要小,那么替换当前最小元素 
          if (index != i) {
              int tmp = test[index];
              test[index] = test[i];
              test[i] = tmp;
          }
      }
    }