C语言 - 堆栈&二叉树的基础及应用

1.历史

        堆栈是为了减少程序内存占用的问题而发明的
        机器上电后,所有的变量都需要copy到内存中运行,但是机器的内存大小一直都是比较有限的,所以堆栈和局部变量两个概念被提出来

2.栈

        每次手动创建、删除变量非常麻烦,于是栈被发明出来

3.堆

        逻辑概念上一棵完全二叉树,从左往右依次遍历满的树也叫完全二叉树
        大根堆:在这棵完全二叉树里,每一棵子树的最大值就是头节点的值
        小根堆:。。。

        用malloc 申请的内存块,用free来释放
        用new 申请的内存块,用delete 来释放

4.heap inset

        在堆的最后添加一个节点,然后和父节点比较,如果当前节点大,就交换
        如果父节点大,就停止

        void heap_insert(int arr[], int n)
        {
            while(arr[n] > arr[(n-1)/2])
            {
                swap(arr[n],arr[(n-1)/2]);
                n = (n-1)>>1;
            }
        }

5.heapify(堆化)

        堆中找到最大值,并去掉:找最大最很简单,因为本来就是最大堆;
        关键在于去掉最大值之后,还要形成最大堆:取堆上的最后一个数字,先放在0位置处, 然后比较0位置和其左右节点的大小,谁大就和谁交换位置,然后对后面的节点执行相同操作,
        那什么时候停止呢:左右节点对比父节点的值小时 or 不再有左右节点

        heapify //堆化过程
        void heapify(int arr[],int index,int heapsize)
        {
         //index从哪个位置开始做堆化
         int left = index*2+1;
         while(left<heapsize)
         {
          int max = left+1<heapsize&&arr[left+1] > arr[left] ? left+1 : left;
          max = arr[max] > arr[index] ? max : index;
  
          if(max == index)
           break; 
          swap(arr,max,index);
  
          index = max;
          left = index*2+1;
         }
        }

      

        Heapinsert & heapify 操作时堆操作中最重要的两个操作;

Other:

        全局变量在程序执行的整个周期都存在,需要占用一定的内存空间
        局部变量使用完之后就把它的内存空间释放掉,即这些变量的生存周期只需要和对应的函数相同即可
        另外:由于局部变量在函数中生成,所以函数copy到别的工程里面还能直接用,如果把函数要用到的变量声明在函数外,那么copy的时候就会比较麻烦

应用:

1.最大堆顶节点删除

        将堆最后的节点放在根节点,然后对跟节点进行heapify

        设现有一个数组,数据全部有序,且符合大根堆的排布,问:如果把其中一个数修改,怎么让他恢复成大根堆的排布
        如果修改的这个值比之前大了,那么就对这个值之前的堆进行heapinsert 操作;
        如果修改的这个值比之前小了,那么就对这个值之后的堆进行heapify操作;
        

2.如果完全二叉树一共有N个节点,那么这个树的高度是多少

         Log(N)级别
        时间复杂度也是和log(N)相关

        那么最后的叶节点,基本上会有N/2个数
        倒数第二层叶节点,会有N/4个数
        T(N) = N/2*1 + N/4*2 + N/8*3 + N/16*4 +…
        等式左右两边分别*2 ,然后用2*T(N) - T(N) = T(N) = O(N)时间复杂度

3.堆排序

        给定一个数组,首先0 - 0 范围是堆
        然后保证0 - 2 范围是堆,同时heapsize一直在变大
        使整个数组变成大根堆,然后把最大值和堆上的最后一个值作交换,同时把heapsize--;

        意思是:当最大值来到堆最后的置位后,把它断开联系,因为它已经到了正确的位置,不需要和堆有联系;
        然后对剩下的堆做heapify,调完之后,继续把堆的最大值和最后位置作交换

        //堆排序
        void heapsort(int arr[],int length)
        {
         if(length<2)
          return;
         for(int i=0;i<length;i++)
         {
          heap_insert(arr,i)     //log(N)  
         }
         int heapsize = length;
         swap(arr,0,--heapsize);
         while(heapsize>0)
         {
          heapify(arr,0,heapsize);//log(N) 
          swap(arr,0,--heapsize);  //额外空间复杂度O(1),因为没有申请额外空间
         }
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bigger_One

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值