Heap Sort Test

140 篇文章 0 订阅
111 篇文章 0 订阅
#include"MyOutput.hpp"


template<typename T>
int idxMax(T a[],int i,int j){
    return a[i] > a[j]?i:j;
}

template<typename T>
void MyAdjustHeap(T a[],int len){
    int lastNonLeafNodeIdx = len/2 - 1;
    bool adjustNext = true;
    while(adjustNext){
        //先调整堆,
        for(int i=lastNonLeafNodeIdx;i>=0;i--){
            int leftChildIdx = 2*i+1;
            int rightChildIdx = 2*i+2;
            if(leftChildIdx < len){
                if(rightChildIdx < len){
                    int childMaxIdx = idxMax(a,leftChildIdx,rightChildIdx);
                    int maxIdx = idxMax(a,i,childMaxIdx);
                    if(i != maxIdx){
                        swap(a+i,a+maxIdx);
                    }
                }
                else{
                    if(a[i] < a[leftChildIdx]){
                        swap(a+i,a+leftChildIdx);
                    }
                }
            }
        }
        //检查堆中是否有不满足的子堆.
        adjustNext = false;
        for(int i=lastNonLeafNodeIdx;i>=0;i--)
        {
            int leftChildIdx = 2*i+1;
            int rightChildIdx = 2*i+2;
            if(leftChildIdx < len){
                if(rightChildIdx < len){
                    if(a[i] < a[leftChildIdx] || a[i] < a[rightChildIdx]){
                        //如果不满足就继续调整
                        adjustNext = true;
                        break;
                    }
                }
                else{
                    if(a[i] < a[leftChildIdx]){
                        //如果不满足就继续调整
                        adjustNext = true;
                        break;
                    }
                }
            }
        }
    }
}

/**
 * 调整一次堆,但不意味着,仅仅一次
 * 堆就调整成为大(小)顶堆,一般那是不可能的.
 * 有可能一次就调整好了.
 * 
 * 调整函数是该算法的核心
 * 这是规律,记住思想或者过程
 * 
 * 这个函数大顶堆
 * 
 */ 
template<typename T>
void adjustHeap(T a[],int i,int len){
    T temp = a[i];
    //从上往下
    for(int k=i*2+1;k<len;k=k*2+1){
        if(k+1 < len && a[k] < a[k+1]){//左右节点比较
            k++;
        }
        if(a[k] > temp){//子节点和根节点比较
            a[i] = a[k];
            i=k;
        }
        else{
            break;
        }
    }
    a[i] = temp;
}


/**
 * 堆排序:
 * 堆 ==> 一颗完美二叉树 (逻辑结构)
 * 存储结构 ==> 线性序列 即 数组 (物理结构).
 * 性质:
 * 1.a[i] 为父节点 则 子节点为 左 a[2*i+1] 右 a[2*i+2]
 * 2.第一个末尾非叶子节点 (度不为0) 的索引(或者下标序号) len(a)/2[整除] - 1;
 * 
 * 
 * 调整大(小)顶堆:
 * 找到a[2*i+1] a[2*i+2] a[i]中的最大值(最小值),交换值,让a[i]保持最大值(最小值)
 * 这样反复调整整个二叉树,就成了大顶堆(小顶堆),这不是二叉排序树,只管堆顶节点值大于(小于)
 * 左右子节点就行了.
 * 
 * 排序过程:
 * 大(小)顶堆已经就序了,就是尾节点和顶点(root)交换,然后排除尾节点,调整除了尾节点以外的堆,
 * 使之成为大(小)顶堆,现在交换这个堆的尾节点和顶点(root),然后再次调整,如此反复只剩下一个节点后,
 * 整个数组的序就已经排好了.
 * 
 * @Reference:
 * @URL = https://www.cnblogs.com/chengxiao/p/6129630.html
 * 
 */ 
template<typename T>
void HeapSort(T a[],int len){
    //对整个完美二叉树的堆进行调整,使之成为堆
    //从下到上,从左到右.
    //整个循环构成了大顶堆
    for(int i=len/2-1;i>=0;i--){
        adjustHeap(a,i,len);
    }
    //交换堆顶元素与末尾元素+调整堆结构
    for(int i=len-1;i>0;i--){
        swap(a,a+i);//将堆顶元素与末尾元素进行交换
        //交换数据后,调整一次就行了,但要从根节点开始调整一次
        //为什么这里调整一次就行了呢?
        //除了根节点不满足,其余的节点都满足,只需要从上到下(三个节点三个节点的调整)调整一次
        //就可以了.画图推导下 除了根节点已经形成的堆的 调节过程.
        adjustHeap(a,0,i);
    }

}


int main(){

    constexpr int len = 10;
    int a[len] = {0};
    createRandomArrayWithBase(a,len,len);
    printlnArr(a,len);
    TimeSpec::begin();
    MyAdjustHeap(a,len);
    TimeSpec::print_cost_time();
    printlnArr(a,len);
    println("===================================");
    constexpr int len2 = 10;
    // int a2[len2] = {9,9,7,5,7,0,0,3,5,6};
    int a2[len2] = {9,7,9,5,6,7,0,3,5,0};
    createRandomArrayWithBase(a2,len2,len2);
    printlnArr(a2,len2);
    TimeSpec::begin();
    // HeapSort(a2,len2);
    for(int i = len2/2-1;i>=0;i--){
        adjustHeap(a2,i,len2);
    }
    TimeSpec::print_cost_time();
    printlnArr(a2,len2);
    println("================堆排序===================");
    constexpr int len3 = 10000;
    // int a2[len2] = {9,9,7,5,7,0,0,3,5,6};
    int a3[len3] = {0};
    createRandomArrayWithBase(a3,len3,len3);
    // printlnArr(a3,len3);
    TimeSpec::begin();
    HeapSort(a3,len3);
    TimeSpec::print_cost_time();
    // printlnArr(a3,len3);
    println("========================");
    constexpr int len4 = 10;
    // int a2[len2] = {9,9,7,5,7,0,0,3,5,6};
    int a4[len4] = {0};
    createRandomArrayWithBase(a4,len4,len4);
    printlnArr(a4,len4);
    TimeSpec::begin();
    HeapSort(a4,len4);
    TimeSpec::print_cost_time();
    printlnArr(a4,len4);


    return 0;
}


[9,2,6,8,0,4,5,7,9,1]
From beginning to end totally costs: 0 s
[9,9,6,8,1,4,5,7,2,0]
===================================
[9,2,6,8,0,4,5,7,9,1]
From beginning to end totally costs: 0 s
[9,9,6,8,1,4,5,7,2,0]
================堆排序===================
From beginning to end totally costs: 0.002 s
========================
[9,2,6,8,0,4,5,7,9,1]
From beginning to end totally costs: 0 s
[0,1,2,4,5,6,7,8,9,9]

Reference:

堆排序参考链接

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值