排序算法——选择排序

一、排序的概念

排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。分内部排序和外部排序,若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。本文所介绍的是内部排序。
二、插入排序

1、概念

  1. 思路:每一次在 n-i+1 (i=1, 2, 3, …, n-1)个记录中选取关键字最小的记录作为有序序列的第 i 个记录。
  2. 分类:直接选择排序、堆排序

2、直接选择排序

直接选择排序:直接选择排序是非稳定的排序方法。在直接选择排序中,共需要进行n-1次选择和交换,每次选择需要进行 n-i 次比较 (1<=i<=n-1), 而每次交换最多需要3次移动,因此,总的比较次数 C=(n*n - n)/2 ,总的移动次数 3(n-1) .由此可知,直接选择排序的时间复杂度为 O(n^2) ,所以当记录占用字节数较多时,通常比直接插入排序的执行速度快些。

思路:第 1 次从 array[0]~array[n-1] 中选取最小值,与 array[0] 交换,…,第 i 次从 array[i-1]~array[n-1] 中选取最小值,与 array[i-1] 交换…,第n-1次从 array[n-2]~array[n-1] 中选取最小值,与 array[n-2] 交换,总共通过n-1次,得到一个从小到大排列的有序序列。所以需要两层循环,第一层循环实现第i次交换,第二层循环实现寻找最小值。

代码如下:

#include <iostream>

using namespace std;

// 选择排序, 每次找到最小的内容放到最开始。
void selectSort(int numArray[], int sum){
    int index = 0;
    // 寻找index~n-1的最小值放到array[index]中。
    for(; index < sum-1; index++){
        int minNum = numArray[index]; //记录最小值的大小
        int minPos = index; // 记录最小值的位置
        // 寻找最小值, 每次遇到更小的元素更新最小值和位置。
        for(int minIndex = index; minIndex < sum; minIndex++){
            if(minNum > numArray[minIndex]){
                minPos = minIndex;
                minNum = numArray[minIndex];
            }
        }
        swap(numArray[index], numArray[minPos]);
    }
}

int main(){
    int sum = 10;
    int arr[100] = {45,10,25,1,9,56,99,100,3,120};
    cout << "排序前:";
    for(int i = 0; i < sum; i++)
        cout << arr[i]<< " ";
    cout << "\n";
    selectSort(arr, sum);
    cout << "排序后:";
    for(int i = 0; i < sum; i++)
        cout << arr[i]<< " ";
    cout << "\n";
    return 0;
}

2、堆排序

堆排序:堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),同时也是非稳定排序。

思路:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将根节点与末尾元素进行交换,此时最大值来到的末尾。然后将剩余n-1个元素重新构造成一个大顶堆,在进行根节点与末尾元素的交换。重复上述步骤,就能够得到一个从小到大的有序序列。

推荐大家看一下这片文章,关于堆排序讲的非常明白详细,不过给出的代码是Java的:https://blog.csdn.net/u010452388/article/details/81283998

C++代码如下:

#include <iostream>

using namespace std;

// 对堆进行调整使其变成大顶堆
void adjustHeap(int numArray[], int pos, int sum){
	// 记录当前堆的根节点,如果根节点关键字比较小会和下面的节点进行交换。
    int tempNum = numArray[pos];
    for(int index = pos*2+1; index < sum; index=index*2+1){
    	// 如果右面的子节点更大,就将位置记录为右节点。
        if(index+1 < sum && numArray[index] < numArray[index+1]){
            index++;
        }
        /*
        如果最开始的根节点值比较当前节点小,把当前子节点赋值到其父节点上
        发生了该步骤,说明根节点比较小,需要更新根节点最终插入的位置。
        */
        if(tempNum < numArray[index]){
            numArray[pos] = numArray[index];
            pos = index;
        }
         /*
        因为最开始根节点的子节点都是大顶堆,
        所以如果根节点比当前节点更大,就不需要往下走了
        */
        else{ 
            break;
        }
    }
    numArray[pos] = tempNum;
}

// 堆排序
void heapSort(int numArray[], int sum){
    for(int start = (sum+1)/2-1; start >= 0; start--){
        adjustHeap(numArray, start, sum);// 对堆进行调整。
    }
    for(int length = sum-1; length>0 ; length--){
        swap(numArray[0], numArray[length]);// 将堆顶元素与末尾元素进行交换。
        adjustHeap(numArray, 0, length);// 重新对堆进行调整。
    }
}


int main(){
    int sum = 10;
    int arr[100] = {45,10,25,1,9,56,99,100,3,120};
    cout << "排序前:";
    for(int i = 0; i < sum; i++)
        cout << arr[i]<< " ";
    cout << "\n";
    heapSort(arr, sum);
    cout << "排序后:";
    for(int i = 0; i < sum; i++)
        cout << arr[i]<< " ";
    cout << "\n";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值