排序——内部排序之选择排序

排序——内部排序之选择排序

简单选择排序

选择排序开始的时候,我们扫描整个列表,找到它的最小元素然后和第一个元素交换,将最小元素放到它在有序表的最终位置上。然后我们从第二个元素开始扫描列表,找到最后n-1个元素的最小元素,再和第二个元素交换位置,把第二小的元素放在它最终的位置上。如此循环下去,在n-1遍以后,列表就排好序了。

算法:
```cpp
void SelectSort(ElemType A[], int n) {
    int min = 0;
    for (int i = 0; i < n-1; i++) {
        min = i;
        for (int j = i + 1; j < n, j++) {
            if (A[j] < A[min])
                min = j;
        }
        if (min != i)
            Swap(A[i], A[min]);
    }
}
```
时间复杂度为O(n^2),空间复杂度为O(1)。

堆排序

1. 堆排序简介: 堆排序是一种树形选择排序的方法,它的特点是:在排序过程中,将L[1…n]看成一棵完全二叉树的顺序存储结构,利用完全二叉树的双亲节点和孩子节点的内在关系,在当前无序区中选择关键字最大的元素。

2. 堆的定义为: 堆分为最大堆和最小堆,其实就是完全二叉树。最大堆要求节点的元素都要不小于其孩子,最小堆要求节点元素都不大于其左右孩子,左右孩子节点之间元素大小不存在大小关系。

3. 基本思想(大根堆):

(1)构造初始堆:
是一个反复筛选的过程,n个节点的完全二叉树,最后一个节点是[n/2]个节点的孩子节点,对[n/2]个节点为根的子树进行筛选,使得该子树成为堆,之后一次向前对各节点[n/2-1…1]为根的子树进行筛选,如果不是堆交换后可能会破坏下一级堆,于是继续采用上述方法构造下一级堆,直到以该节点为根的子树构成堆为止,反复利用这个过程直到根节点。

建立大根堆的算法如下所示:

void BuildMaxHeap(ElemType A[], int len) {
    //  数组下标是从1开始的
    for (int i = len/2; i > 0; i--)
        AdjustDown(A, i, len);
}

void AdjustDown(ElemType A[], int k, int len) {
    //  将元素从k往下进行调整
    A[0] = A[k];   // A[0]暂存元素
    for (int i = 2 * k; i <= len; i *= 2) { 
    //  沿着k较大的子节点向下筛选
        if (i < len && A[i] < A[i+1])  
            i++;
        if(A[0] > A[i]) {
            break;
        } else {
            A[k] = A[i];     //  将子节点的元素调整到双亲节点上;
            k = i;           //  从子节点开始继续往下筛选
        }
    }
    A[i] = A[0];
}

向下调整的时间与树高度h有关,为O(h),建堆的过程中每次向下调整时,大部分节点的高度都比较小,因此可以证明在元素为n个的序列上建堆,其时间复杂度为O(n),说明可以在线性时间内建立一个堆。

(2)排序思路:
将初始待排序关键字序列(R1,R2…Rn)构建成大顶堆,此堆为初始的无序区
将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,…Rn-1)和新的有序区(Rn),由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,…Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2…Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

//  排序算法
void HeapSort(ElemType A[], int len) {
    BuildMaxHeap(A, len);
    for (int i = len; i > 1; i--) {
        Swap(A[i], A[1]);       //  输出堆顶元素
        AdjustDown(A, 1, i-1);  //  把剩余的i-1个元素整理成堆。
    }
}

4. 堆的插入和删除

(1)堆的删除: 由于堆的堆顶元素很有可能是最大的或者是最小的,所以在删除堆顶元素的时候先将堆顶元素与最后一个元素交换,在从堆顶开始向下的调整操作。

**(2)堆的插入:**堆的插入操作将元素插入到末尾,再对新节点进行向上的调整操作,向上调整的算法如下所示:

void AdjustUp(ElemType A[], int k, int len) {
    A[0] = A[k];
    for (int i = k / 2; i > 0; i = k / 2) {
        if (A[i] < A[0]) {
            A[k] = A[i];
            k = i;
        }
    }
    A[k] = A[0]
}

5. 时空复杂度
空间复杂度为O(1), 时间复杂度:建堆时间为O(n),排序的时候向下调整的时间复杂度为O(h),所以时间复杂度为O(nlogn).堆排序不是稳定的排序算法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值