堆和栈的思考

本文深入探讨了内存中的栈区和堆区,阐述了它们的分配方式、特点和区别。栈由操作系统自动管理,适用于局部变量,而堆则需程序员手动分配和释放,适合动态数据。同时,文章介绍了数据结构中的栈和堆,栈遵循先进后出原则,常用于括号匹配问题;堆是一种特殊二叉树,常见于堆排序算法。
摘要由CSDN通过智能技术生成

1. 内存中的堆区和栈区

在这里插入图片描述

1.1 栈区简介

  • 栈由操作系统自动分配和释放,用于存放函数的参数值、局部变量等,通常在函数执行完后就释放,其操作方式类似于数据结构中的栈。
  • 函数中定义的局部变量按照先后定义的顺序依次入栈,即相邻变量的地址之间不会存在其他变量。
  • 栈的内存地址生长方向由高到低。
  • 栈中存储的数据的生命周期随着函数的执行完成而释放。

栈的内存分配
栈内存分配运算内置于CPU的指令集,效率很高,但分配的内存量有限,比如Linux中栈区的大小通常为8M。
只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

1.2 堆区简介

栈上的数据在函数返回的时候就会被释放掉,所以无法将数据传递至函数外部,而全局变量无法动态的产生,只能在编译的时候定义,在这种情况下,堆的使用十分必要。

  • 堆由开发人员分配和释放,分配方式类似于链表。
  • 堆的内存地址生长方向由低到高,但后申请的内存不一定在先申请的内存的后面,原因在于先申请的内存空间一旦被释放,后申请的内存空间则会利用先前被释放的内存
  • 堆中存储的数据若未释放,则其生命周期等同于程序的生命周期。

堆的内存分配
操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该堆结点从空闲结点链表中删除,并将该结点的空间分配给程序。
对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,便于delete语句正确释放本内存空间。此外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多与的那部分重新放入空闲链表中。

1.3 堆区和栈区的区别

栈和堆实际上是操作系统对进程占用的内存空间的两种管理方式,主要有以下区别:

  • 管理方式:操作系统自动分配和释放vs程序员手动分配和释放
  • 空间大小:每个进程拥有的栈大小 ≪ \ll 堆大小
  • 内存生长方向:由高到低vs由低到高
  • 分配方式:栈支持静态分配和动态分配,堆都是动态分配的
  • 分配效率:栈 ≫ \gg
    栈由OS自动分配,会在硬件层级提供支持,分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行。
    堆由C/C++提供的库函数或运算符完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。
  • 存储内容:
    栈:在函数调用时,第一个进栈的是主函数中函数调用语句的下一条可执行语句的地址,然后是函数的各个参数,在大多数的C编译器中,参数是从右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
    堆:一般是在堆的头部用一个字节存放堆的大小,堆的具体内容由程序员安排。

虽然栈效率更高,但相比堆不够灵活。无论是堆还是栈,在内存使用时都要防止非法越界。

2. 数据结构中的堆和栈

2.1 栈

栈是一种运算受限(只允许在表的一端进行插入和删除操作)的线性表,先进后出;栈中只有栈顶的元素才可以被外界使用,因此栈不允许有遍历行为;栈可以使用数组或链表作为底层数据结构,使用数组实现的称为顺序栈,使用链表实现的为链式栈。
栈的应用:括号匹配

//给定一个字符串,里边可能包含“()”和其他字符,请编写程序检查该字符串中的括号是否成对出现。
#include <iostream>
#include <stack>
using namespace std;

bool isValid(string str)
{
    stack<char> s;
    char c;
    int len = str.length();
    for (int i = 0; i < len; i++)
    {
        if (str[i] == '(' || str[i] == '[' || str[i] == '{')
        {
            s.push(str[i]); 
        }
        else if (str[i] == ')')
        {
            if (s.empty()){
                return false;
            }
            else if ((c = s.top())&&(c == '('))
                s.pop();
            else{
                return false;
            }
        }
        else if (str[i] == ']')
        {
            if (s.empty()){
                return false;
            }
            else if ((c = s.top())&&(c == '['))
                s.pop();
            else{
                return false;
            }
        }
        else if (str[i] == '}')
        {
            if (s.empty()){
                return false;
            }
            else if ((c = s.top())&&(c == '{'))
                s.pop();
            else{
                return false;
            }
        }
    }
    if (s.empty())
        return true;
    else
        return false;
}
int main()
{
    string str = "y={x+[x(x+2)]}";
    bool check=true;
    check = isValid(str);
    if (check == true)
        cout << "Valid."<<endl;
    else
        cout << "Not valid."<<endl;
    return 0;
}

2.2 堆

堆是一种常用的树形结构,是一种特殊的完全二叉树,当且仅当满足所有结点的值总是不大于(大顶堆)或不小于(小顶堆)其父节点的值的完全二叉树被称之为堆。
堆一般使用数组进行存储,从左至右从上至下, i i i节点的父节点下标为 i − 1 2 \frac{i-1}{2} 2i1,它的左、右子节点下标分别为 2 i + 1 2i+1 2i+1 2 i + 2 2i+2 2i+2
在这里插入图片描述

堆的应用:堆排序HeapSort
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
基本思想:

  1. 构造初始堆(一般升序采用大顶堆,降序采用小顶堆);
  2. 将堆顶元素和最后一个元素交换,然后将剩下的结点重新构造成一个小顶堆;
  3. 重复步骤2。

代码实现:(以小顶堆为例)

#include <iostream>
using namespace std;

void makeMinHeap(int arr[], int start, int end)
{
    int dad = start;
    int son = 2 * dad + 1;
    while (son <= end)
    {
        if (son + 1 <= end && arr[son] > arr[son + 1])
        {
            son += 1;
        }
        if (arr[dad] < arr[son])
        {
            return;
        }
        else
        {
            swap(arr[dad], arr[son]);
            dad = son;
            son = 2 * dad + 1;
        }
    }
}

void HeapSort(int arr[], int len)
{
    for (int i = len / 2 - 1; i >= 0; i--)
    {
        makeMinHeap(arr, i, len - 1);
    }
    for (int i = len - 1; i > 0; i--)
    {
        swap(arr[0], arr[i]);
        makeMinHeap(arr, 0, i - 1);
    }
    for (int i = 0; i < len; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;
}

int main()
{
    int arr[] = {4, 5, 2, 7, 6, 8};
    int len = sizeof(arr) / sizeof(arr[0]);
    HeapSort(arr, len);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值