데이터 구조 및 알고리즘 기초(Wang Zhuo)(37): 선택 정렬(단순 선택, 힙 정렬)

목차

단순 선택 정렬

힙 정렬

힙 조정:

다겐두이

작은 루트 힙

전체 힙 조정의 전체 프로세스는 다음과 같습니다.

 작업에 따라 프로그램에 주석 달기: (주석을 읽은 후 프로그램이 각 단계에서 어떻게 작동하는지 알 수 있습니다.)

힙 생성

질문


단순 선택 정렬

#include<iostream>
using namespace std;

#define MAXSIZE 20  //记录最大个数
typedef int KeyType;  //关键字类型

typedef int InfoType;

//定义每个记录(数据元素)的结构
struct RecType
    //Record Type:每条记录的类型
{
    KeyType key;  //关键字
    InfoType otherinfo;  //其他数据项
};

struct SqList
    //顺序表(的)结构
{
    RecType r[MAXSIZE + 1];
    //类型为【记录类型】的数组
    //r[0]一般做哨兵或缓冲区
    int length;  //顺序表长度
};

void SelectSort(SqList& L)
{
    for (int i = 1; i <= L.length; i++)
    {
        int k = L.r[i].key;
        for (int j = i; j <= L.length; j++)
        {
            if (L.r[j].key < k)
                k = L.r[j].key;
        }
        if (k != L.r[i].key)
        {
            int temp = L.r[i].key;
            L.r[i].key = k;
            k = temp;
        }
    }
}


int main()
{

}


힙 정렬


힙 조정:

다겐두이

void HeapAdjust(Elem R[], int s, int m) //Heap:堆
//二叉树空间范围:s-m,这里写的是大根堆
// s:smallest
// m:max
{
    //调整R[s]的关键字,使R[s...m]重新成为一个大根堆
    Elem rc = R[s];
    for (int j = 2 * s; j <= m; j *= 2)
    {
        if (j < m && R[j] < R[j + 1])
            j++;  //j为关键字较大的数据元素下标
        if (rc >= R[j])
            break;
        R[s] = R[j];
        s = j;  //记录位置
    }
    R[s] = rc;  //插入
}

처음에 (처음에)이 프로그램을 봤는데 완전히 이해할 수 없었습니다.

우리는 심지어 다음과 같은 질문도 했습니다. 그가 여기에서 마지막 요소를 어떻게 찾았습니까? ? ? 왜 못 봤어?

따라서 먼저 조롱박 그림에 따라 작은 뿌리 더미를 만드는 방법을 생성/찾아 보겠습니다.

작은 루트 힙

void HeapAdjust(Elem R[], int s, int m) //小根堆
{
    Elem rc = R[s];
    for (int j = 2 * s; j <= m; j *= 2)
    {
        if (j < m && R[j] > R[j + 1])
            j++;  //j为关键字较小的数据元素下标
        if (rc <= R[j])
            break;
        R[s] = R[j];
        s = j;  //记录位置
    }
    R[s] = rc;  //插入
}

그런 다음 우리는 오랫동안 프로그램에 조용히 머리를 숙이고 마침내 프로그램이 작성된 내용을 알아 냈습니다.

전체 힙 조정의 전체 프로세스는 다음과 같습니다.

그리고 여기(실제로 우리가 있습니다):

PPT는 실제로 2단계(그림 2)에서 4단계(그림 4)까지 전 과정의 알고리즘을 작성합니다.

tmd 대신 그림 1에서 시작하는 전체 프로세스에 대한 알고리즘

프로그램을 시작할 때 그는 기본적으로 그림 1에서 그림 2까지의 이전 프로세스 작업을 이미 완료했으며 미리 작업을 준비했습니다.

TMD!

 작업에 따라 프로그램에 주석 달기: (주석을 읽은 후 프로그램이 각 단계에서 어떻게 작동하는지 알 수 있습니다.)

작은 뿌리 더미를 예로 들어 보겠습니다. (큰 뿌리 더미도 마찬가지이므로 여기서는 반복하지 않겠습니다.)

void HeapAdjust(Elem R[], int s, int m) //小根堆
{
    Elem rc = R[s];
    //此时最后的元素已经被放到堆顶,rc记录最后一位元素
    for (int j = 2 * s; j <= m; j *= 2)
        //从第二层子树开始遍历
    {
        if (j < m && R[j] > R[j + 1])
            j++; 
        //j:关键字较小的元素下标
        if (rc <= R[j])
            break;
        //要最后一个元素比他小就算了,不然的话:
        R[s] = R[j];
        //j(较小)元素放上面去
        s = j;  
        //下一轮for循环:
        //从上一轮j的位置开始往下遍历
        //以j的位置为根,向下遍历子树,不断把值小的元素移上去
    }
    R[s] = rc; 
    //最后,把最后的元素插入到最底部
    // 注:
    // 最后退出循环的时候s已经指向最底层了
    // 而不出意外的话,最后的元素理论上也应该是堆里面最大的一个元素
}

힙 생성

#include<iostream>
using namespace std;

typedef int Elem;

void HeapAdjust(Elem R[], int s, int m) //小根堆
{
    Elem rc = R[s];
    //此时最后的元素已经被放到堆顶,rc记录最后一位元素
    for (int j = 2 * s; j <= m; j *= 2)
        //从第二层子树开始遍历
    {
        if (j < m && R[j] > R[j + 1])
            j++; 
        //j:关键字较小的元素下标
        if (rc <= R[j])
            break;
        //要最后一个元素比他小就算了,不然的话:
        R[s] = R[j];
        //j(较小)元素放上面去
        s = j;  
        //下一轮for循环:
        //从上一轮j的位置开始往下遍历
        //以j的位置为根,向下遍历子树,不断把值小的元素移上去
    }
    R[s] = rc; 
    //最后,把最后的元素插入到最底部
    // 注:
    // 最后退出循环的时候s已经指向最底层了
    // 而不出意外的话,最后的元素理论上也应该是堆里面最大的一个元素
}

void Swap(int a, int b)
{
    int temp=b;
    b = a;
    a = temp;
}

void HeapSort(Elem R[],int n)
{
    int i;
    for (i = n / 2; i >= 1; i--)  
        HeapAdjust(R, i, n);
    // 我们默认R[]数据无序
    // 先把R[]中的无序数据都排一遍顺序
    // 相当于我们先构造出一个合格的图1

    for (i = n; i > 1; i--)
    {
        cout << R[1] << endl;//逐个输出元素
        Swap(R[1], R[i]);  
        //互换最后一个元素和根
        //相当于执行图1加工到图2的过程

        HeapAdjust(R, 1, i - 1); 
        //面向剩下的元素重新建堆
    }
}

int main()
{

}

​​​​​​​

질문:

 마지막 요소와 루트의 교환이 프로그램 결과에 영향을 미치는지 여부에 대해 걱정할 필요가 없습니다.

루트릿 힙을 정렬할 때:

마지막 요소, 즉 가장 큰 요소는 이진 트리 하위 트리에서 더 큰 값을 가진 쪽에 있어야 합니다.

그리고 후속 순회 정렬에서 우리가 변경하는 것은 이진 트리 하위 트리의 값이 더 작은 쪽이므로 영향이 없어야 합니다.

Dagendui도 마찬가지이므로 반복하지 않겠습니다.

추천

출처blog.csdn.net/Zz_zzzzzzz__/article/details/130461642