堆排序

来源:互联网 发布:2016域名价格排行榜 编辑:程序博客网 时间:2024/05/21 17:59
时间复杂度:O(nlgn)空间复杂度:O(1)最关键的问题:创建大根堆

关键:创建大根堆

/*说明:堆排序是完全二叉树顺序存储的应用,存储在数组中。Q1:假设有N个结点进行堆排序,那么存储在数组中的下标是1~N,0下标不使用。   为什么用1~N,而不是用0~N-1下标呢?A1:(1)由父子结点的关系决定的  (2)还有一个重点应用:A[0]在向下调整    函数AdjustDown函数中保存着i的父节点k的值。Q2:AdjustDown(A, i, len)函数每执行一次,至多调整几个值?A2:最初认为最多能调整一个值,其实不然,最多可以调整值的个数是(树高-父节点i所在高度+1)。    AdjustDown(A, i, len)函数在每次调整完一次父节点i的值后,要更新父节点i变成i的子节点,    然后在进行调整判断,...,如此循环往复,直到退出循环。Q3:创建大根堆函数BuildMaxHeap中调用AdjustDown调整函数的调用方向-->是从    第一个父节点到最后一个父节点?还是从最后一个父节点到第一个父节点?A3:根据堆排序创建大根堆过程,可得:调整方向是从最后一个父节点,到第一个父    节点-->因此循环是for(int i=len/2;i>=1;i--)*/#include<stdio.h>/*A[0]: 始终存放着每一次循环的父节点的值k: 始终存放着每一次循环的父节点的下标位置i: 始终存放着k父节点左右结点较大的值for循环的范围是左孩子结点i的范围    for(int i=2*k;i<=len;i*=2)for循环中,    更新父节点更新的是父节点的下标位置*/void AdjustDown(int A[], int k, int len)  //k是要调节的父节点{    A[0] = A[k]; //将k父节点的值赋值给A[0],A[0]始终保存着每个父节点的值    //调节是一个循环的过程,因此写个循环    for (int i = 2 * k; i <= len; i *= 2)  //i节点初始为父节点k的左孩子    {        //在保证有右孩子的基础上,判断k的右孩子是否大于左孩子        if (i+1<=len && A[i] < A[i + 1]) //i+1<=len表示右孩子在数组中,右孩子存在            i++;        if (A[i] > A[0])  //如果孩子i大于父节点,进行处理        {            A[k] = A[i];  //将左孩子的值赋值给父节点            k = i;  //更新左孩子i变成新的父节点,用于下一次循环        }        else  //若孩子i不大于父节点,则证明下面已经全部符合大根堆要求,直接break出for循环            break;    }    //执行完所有的for循环调整后,不要忘记把A[0]中存储的最初的父节点A[k]赋值给当前父节点k    A[k] = A[0];}void BuildMaxHeap(int A[], int len){    for (int i = len / 2; i >= 1; i--)    {        AdjustDown(A, i, len);    }}int main(){    int A[] = { 0,53,17,78,9,45,65,87,32 };    int length = sizeof(A) / sizeof(A[0]);    BuildMaxHeap(A, length);    for (int i = 1; i < length; i++)        printf("%5d", A[i]);    printf("\n");}

这里写图片描述

堆排序

#include<stdio.h>/*A[0]: 始终存放着每一次循环的父节点的值k: 始终存放着每一次循环的父节点的下标位置i: 始终存放着k父节点左右结点较大的值*/void AdjustDown(int A[], int k, int len)  //k是要调节的父节点{    A[0] = A[k]; //将k父节点的值赋值给A[0],A[0]始终保存着每个父节点的值    //调节是一个循环的过程,因此写个循环    for (int i = 2 * k; i <= len; i *= 2)  //i节点初始为父节点k的左孩子    {        //在保证有右孩子的基础上,判断k的右孩子是否大于左孩子        if (i+1<=len && A[i] < A[i + 1]) //i+1<=len表示右孩子在数组中,右孩子存在            i++;        if (A[i] > A[0])  //如果孩子i大于父节点,进行处理        {            A[k] = A[i];  //将左孩子的值赋值给父节点            k = i;  //更新左孩子i变成新的父节点,用于下一次循环        }        else  //若孩子i不大于父节点,则证明下面已经全部符合大根堆要求,直接break出for循环            break;    }    //执行完所有的for循环调整后,不要忘记把A[0]中存储的最初的父节点A[k]赋值给当前父节点k    A[k] = A[0];}void BuildMaxHeap(int A[], int len) //创建大根堆{    for (int i = len / 2; i >= 1; i--)    {        AdjustDown(A, i, len);    }}void swap(int &a, int &b){    int t = a; a = b; b = t;}void HeapSort(int A[], int len)  //堆排序{    for (int i = 1; i <= len; i++)    {        BuildMaxHeap(A, len - i + 1);        swap(A[1], A[len - i + 1]);    }}int main(){    int A[] = { 0,5,17,7,9,5,65,87,32 };    int length = sizeof(A) / sizeof(A[0]);    HeapSort(A, length-1);    for (int i = 1; i < length; i++)        printf("%5d", A[i]);    printf("\n");}

堆排序的应用题:
这里写图片描述

#include<stdio.h>void AdjustDown(int A[], int k, int len)  //k是要调节的父节点{    A[0] = A[k]; //将k父节点的值赋值给A[0],A[0]始终保存着每个父节点的值    //调节是一个循环的过程,因此写个循环    for (int i = 2 * k; i <= len; i *= 2)  //i节点初始为父节点k的左孩子    {        //在保证有右孩子的基础上,判断k的右孩子是否大于左孩子        if (i + 1 <= len && A[i] > A[i + 1]) //i+1<=len表示右孩子在数组中,右孩子存在            i++;        if (A[i] < A[0])  //如果孩子i大于父节点,进行处理        {            A[k] = A[i];  //将左孩子的值赋值给父节点            k = i;  //更新左孩子i变成新的父节点,用于下一次循环        }        else  //若孩子i不大于父节点,则证明下面已经全部符合大根堆要求,直接break出for循环            break;    }    //执行完所有的for循环调整后,不要忘记把A[0]中存储的最初的父节点A[k]赋值给当前父节点k    A[k] = A[0];}//创建小根堆void BuildMinHeap(int A[], int len)  {    for (int i = len / 2; i >= 1; i--)    {        AdjustDown(A, i, len);    }}void swap(int &a, int &b){    int t = a; a = b; b = t;}//堆排序void HeapSort(int A[], int len){    for (int i = 1; i <= len; i++)    {        BuildMinHeap(A, len - i + 1);        //printf("%5d", A[1]);        swap(A[1], A[len - i + 1]);    }}int main(){    int A[] = { 0,2, 1, 4, 3, 6, 5, 8, 7, 10, 9 };    int k = 2;    int kk = k;    int len = sizeof(A) / sizeof(A[0]) - 1;       int *B = new int[len + 1];    for (int i = k, j = 1; k <= len;)  //排序1~N-K+1个    {        BuildMinHeap(A, 2);        B[j++] = A[1];        //printf("%5d", A[1]);        A[1] = A[++k];    }    //剩下的N-K+2~N个结点用堆排序    A[1] = A[kk];    HeapSort(A, kk-1);    for (int i = 1; i <= len; i++)        printf("%5d", B[i]);    printf("\n");}
原创粉丝点击