【数据结构】排序:选择排序(简单选择排序、堆排序等)详解与实现(C++)

#笔记整理

内部排序分类目录:
插入排序
交换排序
->选择排序
归并排序
– 计数排序

选择排序

基本思想:每一趟 (第 i 趟,i = 1, …, n-1) 在后面 n-i+1 个待排序记录中选出关键字最小的记录, 作为有序序列的第 i 个记录。

简单选择排序(Simple Selection Sort)

通过 n − i n-i ni 次关键字间的比较,从 n − i + 1 n-i+1 ni+1 个记录中选取关键字最小的记录,并和第 i i i个记录交换。

算法实现:

	// 简单选择排序法,对容器或数组nums进行排序
    void sSelectionSort(vector<int> &nums){
        int len = nums.size();
        for(int i = 0; i < len - 1; i++){
            int currMinIndex = i;                 // 最小记录的下标
            for(int j = i + 1; j < len; j++ ){
                compareCount++;
                if(nums[j] < nums[currMinIndex]){
                    currMinIndex = j;
                }
            }
            swap(nums[i], nums[currMinIndex]);    // 将最小记录与当前记录nums[i]进行交换。
        }
    }

github源码

《【数据结构】排序:选择排序(简单选择排序、堆排序等)详解与实现(C++)》

简单选择排序是一种不稳定的排序方法,如对{2, 2’, 1}排序。

冒泡排序法与选择排序法相比,一个从局部入手减少逆序元素,一个放眼大局逐个选择最小值,二者思路大不相同,但是,它们又都有着 “通过 i 次外层循环,从数据中顺次求出 i 个最小值” 的相同特征。

堆排序(Heap Sort)

是具有下列性质的完全二叉树:
当每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆。
当每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。

而堆排序算法是把顺序存储的数据看成是一棵完全二叉树,利用堆进行排序的方法。
基本思想:
对一组待排序记录的关键字,首先把它们按堆的定义建成小(大)顶堆,然后输出堆顶的最小(大)关键字所代表的记录,再对剩余的关键字建堆,以便得到次小(大)的关键字,如此反复进行,直到全部关键字排成有序序列为止。

算法实现:

	// 堆排序法的堆调整函数,已知nums[low ~ high] 中的记录除 nums[low]之外均满足大顶堆的定义,
    // 向下调整 nums[low], 使 nums[low ~ high] 中记录均满足大顶堆的定义
    void heapAdjust(vector<int> &nums, int low, int high){
       int temp = nums[low];                                    // 利用临时变量存储待调整数据
       for(int j = 2 * low + 1; j <= high; j = 2 * j + 1){      // 沿值较大的孩子结点向下筛选
           if( j < high && nums[j] < nums[j + 1]){              // 左孩子小于右孩子
                j++;                                            // j 为值较大的记录的下标,即 j 指向[low]的右孩子
           }
           if(temp >= nums[j]){                                 // [low]的值大于或等于[j]的值
                break;                                          // 不必再调整,跳出for循环
           }
           nums[low] = nums[j];                                 // 否则,[j]为大顶,插入[low]
           low = j;                                             // [low]的位置向下移到[j],即原左或右孩子处
       }
       nums[low] = temp;                                        // 将待调整的记录插入[low]
    }

    // 堆排序法,对容器或数组nums进行排序
    void heapSort(vector<int> &nums){
        int len = nums.size();
        int i;
        for(i = len / 2 - 1; i >= 0; i--){                        // 从最后一个非叶子子结点到[0]
            heapAdjust(nums, i, len - 1);                        // 调整nums[i],使nums[i ~ len-1] 成为大顶堆
        }

        for(i = len - 1; i > 0; i--){
            swap(nums[0], nums[i]);                              // 交换堆顶记录[0]和未完全排序的nums[1 ~ i]中的最后一个记录[i]
            heapAdjust(nums, 0, i - 1);                             // 调整nums[0],使num[0 ~ i-1]重新成为大顶堆
        }
    }

github源码

《【数据结构】排序:选择排序(简单选择排序、堆排序等)详解与实现(C++)》
堆排序是一个不稳定的排序方法。


树形选择排序(锦标赛排序)

算法思路:
n 个记录的关键字,进行两两比较,得到 n/2 个比较的优胜者(关键字小者),作为第一步比较的结果保留下来。然后对这 n/2 个记录再进行关键字的两两比较,…,如此重复,直到选出一个关键字最小的记录为止。
(此算法用的不多,实现暂时略过,以后有时间再补充)
《【数据结构】排序:选择排序(简单选择排序、堆排序等)详解与实现(C++)》
锦标赛排序是一个稳定的排序方法。

部分内容来源:

  1. 《数据结构(C语言版)》—-严蔚敏
  2. 《数据结构》课堂教学ppt —- 刘立芳
  3. 《数据结构算法与解析(STL版)》 —- 高一凡
  4. 《大话数据结构》 —- 程杰
  5. 《挑战程序设计竞赛2:算法和数据结构》 —- 渡部有隆
点赞