栈和队列

计算机中的内存管理

类型

内核

指操作系统内核,是操作系统的核心组件,负责管理系统资源

堆区

主要用于动态内存分配(malloc/free)

栈区

用于存储程序执行期间的临时变量,如函数调用的参数、局部变量和返回地址。栈的内存分配和回收是自动的。

数据区

数据区通常用于存储全局变量和静态变量。这个区域可以进一步分为初始化数据区(用于存储初始

化的全局变量和静态变量)和未初始化数据区(也称为 BSS 段,用于存储未初始化的全局变量和

静态变量)。

文本区

文本区或代码区用于存储程序的执行代码,也就是 CPU 执行的机器指令。


栈区

存放的数据类型

1.局部变量

函数内的局部变量通常存储在栈上。当函数被调用时,其局部变量被创建并推入栈中,函数执行完

毕后,这些变量随栈帧(stack frame)一起被销毁

2.函数参数

函数的形参和返回值通常存放在栈区

3.返回地址

栈区在函数进行函数调用时,会保存调用的函数的入口地址(保护现场)

保护现场和恢复现场的规则:先入后出,后入先出

4.递归调用的嵌套关系

在递归函数中,每次递归调用都会生成一个新的栈帧,包含该调用的局部变量和返回地址,这些栈

帧在递归调用返回时被销毁

数据栈(通常的“栈”)和系统栈(调用栈)的区别与联系

用途

数据栈:用于存储程序运行时的临时数据,如表达式求值、函数调用的中间结果等

系统栈:用于跟踪函数调用的顺序和状态,包括存储局部变量、参数、返回地址和函数的执行环境

控制方式

数据栈:由程序员在代码中通过栈操作函数控制

系统栈:由操作系统和运行时环境自动管理,例如在函数调用和返回时自动压栈和出栈

作用域

数据栈:用于存储不同作用域的数据,但通常用于局部作用域

系统栈:用于存储函数调用的作用域信息,每个函数调用都有自己的栈帧

相同之处

LIFO(后进先出)原则:无论是数据栈还是系统栈,都遵循 LIFO 的原则,即最后进入的元素会第一个被移除

栈操作:两者都使用类似的基本操作,如 push(压栈)和 pop(出栈),来添加和移除元素

内存管理:它们都涉及到内存的分配和释放。数据栈和系统栈在添加元素时分配内存,在移除元素时释放内存

数据结构:从数据结构的角度看,它们都是栈这种抽象数据类型的实现,无论是在硬件层面还是软件层面


数据栈(栈)

栈结构

只允许从一端进行数据的插入和删除的线性的存储结构

数据插入:入栈,压栈

数据出栈:出栈,弹栈

数据栈分类

顺序栈:用数组实现

链式栈:用链表实现

1.创建栈

Stack_t *create_stack()
{
    Stack_t *pnode = malloc(sizeof(Stack_t));
    if(NULL == pnode)
    {
        return NULL;
    }

    pnode->ptop = NULL;
    pnode->clen = 0;

    return pnode;
}

2.入栈

int push_stack(Stack_t *pnode,DataType data)
{
    SNode_t *psnote = malloc(sizeof(SNode_t));
    if(NULL == psnote)
    {
        return -1;
    }
    psnote->data = data;
    psnote->pnext = pnode->ptop;
    pnode->ptop = psnote;
    pnode->clen++;

    return 0;
}

3.出栈

int pop_stack(Stack_t *pnode,DataType *data)
{
    if(is_empty_stack(pnode))
    {
        return 0;
    }
    *data = pnode->ptop->data;
    SNode_t *pdel = pnode->ptop;
    pnode->ptop = pdel->pnext;
    free(pdel);
    pnode->clen--;
    return 0;
}

4.清空栈

void clear_stack(Stack_t *pnode)
{
    if(is_empty_stack(pnode))
    {
        return;
    }
    SNode_t *psnote = pnode->ptop;
    while(psnote != NULL)
    {
        SNode_t*ptmp = psnote;
        psnote = psnote->pnext;
        free(ptmp);
    }
    pnode->ptop = NULL;
    pnode->clen = 0;
}

5.判空

int is_empty_stack(Stack_t *pnode)
{
    return NULL == pnode->ptop;
}

6.获取栈顶元素

int get_stack_top(Stack_t *pnode,DataType *data)
{
    if(is_empty_stack(pnode))
    {
        return 0;
    }
    *data = pnode->ptop->data;
    //SNode_t *psnote = pnode->ptop;
    return 0;
}

7.销毁栈

void destory_stack(Stack_t *pnode)
{
    clear_stack(pnode);
    free(pnode);
}

栈结构:满增栈 满减栈 空减栈 空增栈

满栈、空栈:

满栈的入栈顺序,先移动栈顶,再入栈数据

空栈的入栈顺序:先入栈一个数据,再移动栈顶

出栈顺序:先移动的栈顶,再移出数据

增栈、减栈:

增栈:无论是满栈还是空栈,加入数据后,栈顶是由内存低地址移向高地址就是增栈

减栈:栈顶由高内存地址移项低内存地址


队列

允许从一端插入数据,另一端删除数据的线性的存储结构

队尾:插入数据 入队

队头:取出数据 出队

先进先出,后进后出 FIFO

管道的本质就是一个队列

缓冲区:匹配高速设备和低速设备之间的效率问题

队列就可以作为缓冲区来解决高低速设备之间传输时的效率

队列和栈之间的区别

数据访问原则

:遵循后进先出(LIFO,Last-In-First-Out)的原则,即最后添加到栈的元素会第一个被移除。

队列:遵循先进先出(FIFO,First-In-First-Out)的原则,即最先添加到队列的元素会第一个被移除。

操作方式

:主要操作包括 push(在栈顶添加元素)和 pop(从栈顶移除元素)。     

       还有一个 peek 或 top 操作,用来查看栈顶元素但不移除它

队列:主要操作包括 enqueue(在队尾添加元素)和 dequeue(从队首移除元素)。

            同样有 front 操作,用来查看队首元素但不移除它。

使用场景

:常用于处理具有递归结构的问题,如函数调用堆栈、表达式求值、括号匹配、回溯算法等。

队列:常用于处理消息队列、任务调度、广度优先搜索算法、打印机任务排队等场景。

内存利用率

:由于其 LIFO 的特性,栈的内存利用率通常较高,因为栈顶的内存可以快速地被重新利用。

队列:可能需要更多的内存,因为元素在队列中停留的时间可能更长,直到它们到达队首被移除。

队列分类:

顺序队列:数组 ------>存在假溢出问题,所以一般使用顺序队列的时候用循环顺序队列

链式队列:链表

1.创建队列

Queue_t *create_queue()
{
    Queue_t *qnode = malloc(sizeof(Queue_t));
    if(NULL == qnode)
    {
        return NULL;
    }
    qnode->pfront = NULL;
    qnode->ptail = NULL;
    qnode->clen = 0;
    
    return qnode;
}

2.入队

int push_queue(Queue_t *qnode,QDataType data)
{
    QNode_t *plink = malloc(sizeof(QNode_t));
    if(NULL == plink)
    {
        return -1;
    }
    plink->pnext = NULL;
    plink->data = data;
    if(is_empty_queue(qnode))
    {
        qnode->pfront = plink;
        qnode->ptail = plink;
        qnode->clen = 1;
    }
    else
    {
        qnode->ptail->pnext = plink;
        qnode->ptail = plink;
        qnode->clen++;
    }
    return 0;
}

3.出队

int pop_queue(Queue_t *qnode,QDataType *data)
{
    if(is_empty_queue(qnode))
    {
        return 0;
    }
    QNode_t *p = qnode->pfront;
    if(p->pnext == NULL)
    {
        qnode->pfront = NULL;
        qnode->ptail = NULL;
        qnode->clen = 0;
    }
    else
    {
        qnode->pfront = p->pnext;
        qnode->clen--;
    }
    *data = p->data;
    free(p);
    return 0;
}

4.清空队列

void clear_queue(Queue_t *qnode)
{
    while(!(is_empty_queue(qnode)))
    {
        QNode_t *p = qnode->pfront;
        qnode->pfront = p->pnext;
        free(p);
        if(qnode->pfront == NULL)
        {
            qnode->ptail = NULL;
            qnode->clen = 0;
        }
    }
}

5.判空

int is_empty_queue(Queue_t *qnode)
{
    return NULL == qnode->pfront;
}

6.获取栈顶元素

int get_queue_front(Queue_t *qnode,QDataType *data)
{
    if(is_empty_queue(qnode))
    {
        return 0;
    }

    *data = qnode->pfront->data;
    return 0;
}

7.销毁栈

void destory_queue(Queue_t *qnode)
{
    if(qnode != NULL)
    {
        clear_queue(qnode);
        free(qnode);
        qnode = NULL;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值