408数据结构学习笔记——简单选择排序、堆排序

简介: 408数据结构学习笔记——简单选择排序、堆排序

1.简单选择排序

1.1.算法思想

遍历数组,每次找到一个最小的元素插入到表头位置

1.2代码

//交换元素
void swap(int &a, int &b){
    int temp = a;
    a = b;
    b = temp;
}
//简单选择排序
void SelectSort(int arr[], int n){
    //遍历数组
    for (int i = 0; i < n; i++){
        //标记当前数组中最小值元素的下标,初始为第 i 个元素
        int min = i;
        //从i + 1开始遍历数组
        for (int j = i + 1; i < n; j++){
            if (arr[j] < arr[min]) min = j;
        }
        //交换第 i 个元素和最小值元素
        swap(arr[i] , arr[j]);
    }
}

1.3.时间复杂度和稳定性

1.时间复杂度:

最好情况:有序,进行0次移动

最坏情况:逆序,进行不超过3(n - 1)次移动

无论有序还是无序,都需要进行n ( n - 1) / 2次比较,区别仅在于移动次数,因此,O(n^2)

2.空间复杂度O(1)

3.稳定性:不稳定

4.适用性:顺序和链式

2.堆排序

2.1.算法思想

A.堆的本质是一棵完全二叉树

大根堆:根 >= 左右子树 L(i) >= L (2i) && L(i) >= L(2i + 1) (2i 和 2i + 1 为根节点的左右子树)

小根堆:根 <= 左右子树 L(i) <= L (2i) && L(i) <= L(2i + 1)

B.每一趟将大根堆的堆顶元素加入有序子序列(与待排序序列中的最后一个元素交换),交换后,对待排序序列重新进行大根堆的调整

1.堆顶元素为87,与9交换,且堆元素 - 1

ebbeca7fe53e4bcb9fbb7fdc18e0e8d5.png

2.9不满足大根堆的定义,开始下坠

826233267d9040e799f6789cfe9d5009.png

3.9的左右孩子分别为45和78→78 > 45→78 > 9→9与78交换

4ea09cc10d9d42acb61e23729acea4eb.png

4.9的左右孩子分别为65和53→65 > 53→65 > 9→9与65交换

201adee69c844a0b8e7598b685e980cd.png

5.堆中元素符合大根堆定义;将堆顶元素78与数组中最后一个元素53对换,堆元素 - 1c5a570e408854d7789dc233efe3fba24.png

6.53的左右孩子分别为45和65→65 > 45→65 > 53→53与65交换

c86c8a9ebebc43988a7e227c60d7fdca.png

7.堆中元素满足大根堆定义;堆顶元素65与堆中最后一个元素9交换

504ba9e91fc04a80a90bbf4ee9739324.png8.9的左右孩子分别为45和53→53 > 45→53 > 9→09与53交换

4de58c563bcb4beeae8e1206c37562f6.png

9.堆中元素满足大根堆定义;堆顶元素53与堆中最后一个元素17交换

ee3d0c35eb7c4ffcbfb24924c27b6240.png

10.17的左右孩子分别为45和09→45 > 09→45 > 17→17与45交换


5abdc44c771e4fac8ea5da106d4759d4.png

11.17只有左孩子32→32 > 17→32与17交换

51363a6052a74c1a9f09deacf9577128.png

12. 堆中元素满足大根堆定义;堆顶元素45与堆中最后一个元素17交换

0fdd262d5c7d4df4a1e2710d45a16b34.png13.17的左右孩子分别为32和09→32 > 09→32 > 17→17与45交换


6ba095f338964bc18511fa9e6d6ab598.png

14.堆中元素满足大根堆定义;堆顶元素32与堆底元素09交换,堆元素-1

820ca3902be54d398ce16a32b7db5e6b.png

15.09只有左孩子17→17 > 09→09与17交换 d2447ee55b7a478dac0006b2d9b17b01.png

16.堆顶元素17与堆底元素09交换,堆元素-1,此时堆中只有一个元素,排序结束

db353614b7564af8af1dc274d7241d94.png

2.2代码

2.2.1大根堆的建立

把所有非终端结点(i <= n / 2)遍历一遍,检查是否符合大根堆 / 小根堆的特性(从后往前):

A.不满足,左右孩子先进行一次判断,找到更大的孩子

B.判断根节点是否满足大于这个更大的孩子,即根 >= 左右孩子,不满足,则与这个孩子交换

C.若进行B的交换操作,则有可能破坏了下一级的堆的特性,则采用相同方式对下一级进行调整(递归,元素不停下坠)

注意:外层循环的 i 是 <= len,判断的是 i 该元素是否有孩子;而内层循环中的 i 是 < len,此时需要判断是否有右兄弟

//调整以k为子树的大根堆
void HeadAdjust(int arr[], int len, int k){
    //数组下标0保存第k个元素
    arr[0] = A[k]
    //找到第k个元素的左孩子
    for (int i = 2 * k; i <= len; i *= 2) {
        //判断左右孩子谁更大
        if (i < len && arr[i] < arr[i + 1]) i++;
        //根节点大于孩子结点中更大的结点,跳出循环
        if (arr[k] > arr[i]) break;
        //小于,则孩子结点和根节点的值和下标都交换
        else {
            arr[k] = arr[i];
            k = i;
        }
    }//for
    //原根节点的值放入最终位置
    arr[k] = arr[0];
}
void BuildMaxHeap(int arr[], int len) {
    //从分支节点开始往上遍历调整
    for (int i = len / 2; i > 0; i--) {
        HaedAdjust(arr, len, i);
    }
}

2.2.2.大根堆排序

//交换元素
void swap(int &a, int &b){
    int temp = a;
    a = b;
    b = temp;
}
//大根堆调整
void HeapAdjust(int arr[], int k, int len){
    arr[0] = arr[k];
    for (int i = 2 * k; i <= len; i *= 2) {
        if (i < len && arr[i] < arr[i + 1] ) i++;
        if (arr[k] > arr[i]) break;
        else {
            arr[k] = arr[i];
            k = i;
        }
    }
    arr[k] = arr[0];
}
//大根堆的建立
void BuildMaxHeap(int arr[], int len){
    for (int i = len / 2; i > 0; i++){
        HeapAdjust(arr, i, len);
    }
}
//大根堆排序
void HeapSort(int arr[], int len){
    //初始化堆
    BuildMaxHeap(arr, len);
    //循环往前遍历数组
    for (int i = len; i > 1; i++) {
        //交换堆顶元素和堆底元素
        swap(arr[i], arr[1]);
        //调整数组的无序部分
        HeapAdjust(arr, i -1, i);
    }
}

2.3.时间复杂度和稳定性

1.时间复杂度:O(nlog2n)

A.建堆过程比较次数不超过4n,建堆复杂度O(n)即BuildMaxHeap

B.排序总共进行n - 1趟:根节点最多下坠h - 1层,最多对比2次关键字,不超过O(h) = O(log2n)(树高)因此,每趟时间复杂度为(log2n)

2.稳定性:不稳定

2.4.小根堆的插入

A.将新元素插入表尾

B.然后与其双亲结点进行比较,若小于双亲结点,则与双亲结点进行交换

C.循环B直到该结点大于双亲结点

1.在堆底插入13

af02b169f42648f79030613d93146c94.png2.13 < 根节点32→13和32交换


13111a204da54b9eb1879c81fa7d1a43.png

2.13 < 根节点17→13和17交换;交换后13 > 根节点09,满足小根堆定义,停止上升9fd6d35fc96f4d7d9146d808c764f450.png

2.5.小根堆的删除

A.用堆底元素E移动被删除元素的位置

B.比较E的孩子结点,找到更小的孩子结点MIN,若MIN < E,则进行交换

C.循环进行B,直到E无法继续下坠

1.删除13

624dad3828594304b4c0ea9824afc1c4.png 2.让堆底元素移动到原13在数组中的位置

dcffba367ccf480aa0d51a5e8125bf12.png

3.46的左右孩子分别为17和45→17 < 45→17<46→17与46交换;交换后满足小根堆定义,停止下坠

bf335c7eaba047da822325673246688a.png4.46的左右孩子分别为53和32→32 < 53→32<46→32与46交换;

be9e3c97362a4cb6aed556d87cdef7a5.png

3.王道课后题c02efc1c73eb479a93fc199ccfb8af77.png

typedef struct LNode{
    struct LNode *next;
    elemtype data;
}LNode, *LinkList;
LinkList SelectSort(LinkList &L){
    LNode *p = L->next, *last = L;
    L->next = NULL;
    //循环直到p指向空
    while (p) {
        //s用于遍历数组,min用于标记当前已遍历链表的最小值
        LNode *s = p, pre = NULL, min = s, minpre = NULL;
        while (s) {
            //找到最小值,更新min和minpre
            if (s->data < minNode->data) {
                minpre = pre;
                min = s;
            }
            //s和pre向后移
            pre = s;
            s = s->next;
        }
        //当前链表剩余至少两个元素,修改当前元素的前驱的next指针
        if (minpre) minpre->next = min->next;
        //将该元素插入L后(尾插法)
        last->next = min;
        last = last->next;
    }
    //last的next置空
    last->next = NULL;
    return L;
}

aa5d7629ba0d41ba945853004667f2b9.png

bool IsMinHeap(int arr[], int len){
    //从数组下标为1开始作为数组第一个元素开始向后遍历
    for (int i = 1; i < n / 2; i++){
        //k为左孩子,j为右孩子
        int k = 2i, j = 2i + 1;
        //当前元素大于左孩子,返回false
        if (arr[i] > arr[k]) return false;
        //判断右孩子是否存在
        else if (j <= len) {
            //当前元素大于右孩子,返回false
            if (arr[i] > arr[k) return false;
        }
    }
    //循环结束,返回true
    return true;
}










相关文章
|
1月前
|
算法
数据结构——堆的应用 堆排序详解
数据结构——堆的应用 堆排序详解
数据结构——堆的应用 堆排序详解
|
1月前
|
搜索推荐 算法
【数据结构】排序之插入排序和选择排序
【数据结构】排序之插入排序和选择排序
|
1月前
【数据结构】插入排序、选择排序、冒泡排序、希尔排序、堆排序
【数据结构】插入排序、选择排序、冒泡排序、希尔排序、堆排序
|
1月前
|
算法 搜索推荐 C语言
C语言数据结构之排序整合与比较(冒泡,选择,插入,希尔,堆排序,快排及改良,归并排序,计数排序)
C语言数据结构之排序整合与比较(冒泡,选择,插入,希尔,堆排序,快排及改良,归并排序,计数排序)
|
1月前
|
搜索推荐
【数据结构】插入排序,希尔排序,选择排序,堆排序,冒泡排序
【数据结构】插入排序,希尔排序,选择排序,堆排序,冒泡排序
29 3
|
1月前
【数据结构】堆排序和top-K问题
【数据结构】堆排序和top-K问题
30 3
|
2月前
|
搜索推荐 算法 Java
【数据结构排序算法篇】----堆排序【实战演练】
【数据结构排序算法篇】----堆排序【实战演练】
25 2
|
2月前
|
搜索推荐 算法 索引
【数据结构排序算法篇】----选择排序【实战演练】
【数据结构排序算法篇】----选择排序【实战演练】
23 0
|
3月前
|
搜索推荐 C语言
数据结构排序——选择排序与堆排序(c语言实现)
数据结构排序——选择排序与堆排序(c语言实现)
22 0
|
3月前
|
搜索推荐
【数据结构】树结构应用(堆排序、赫夫曼树、赫夫曼编码)
【数据结构】树结构应用(堆排序、赫夫曼树、赫夫曼编码)
43 0

热门文章

最新文章