码迷,mamicode.com
首页 > 其他好文 > 详细

栈导论

时间:2018-06-26 22:35:47      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:str   type   高效   思想   清理   ast   int   RoCE   必须   

本篇文章主要起到引子的作用,而并非去研究栈结构、或者说堆栈在操作系统内部的机制。
学习很久的栈,通过汇编语言来学习栈、C数据结构去实现的栈,正因为感觉栈太过于深秒,无法表述更好,所以只是一个导论,说说学习心得。
栈的特点:后进先出(Last in first out),这就是栈的精髓,我们知道在内存中其实都是线性存储,他可以是栈段,也可以是数据段,更可以是其余的内存空间
以8086CPU(16位)举列说明,只要是被ss:sp(基础段寄存器+偏移地址)所指向的地址,这就是栈内存,那么通过上面叙述我们应该考虑,竟然没有具体的告诉那是栈内存,那不是无限大?你可以这样理解,凡是电脑能够寻址到的内存空间(必须是段寄存器ss+偏移地址)就可以认为是栈内存,那么栈溢出,栈下线等问题就成了安全的重要话题。
那么我们CPU是如何来进行入栈、出栈等操作呢,首先栈底、栈顶两个概念。栈底也就是栈的底部,栈顶也就是栈的最高点,都说了内存中没有说哪一个空间是栈的空间,何来的栈顶与栈底呢?其实就是我们人为设置的,大家想象出来的,这一点与先进后出的思想大同小异,更是栈的思想,只要让这些数据遵循着这些规则,那么就是栈。初始化栈我们一般认为都是把指针指向栈底,其实不然在内存中寄存器会指向栈底的下一个单元,为什么?
1、Push操作,内存中高地址在下,低地址在上面(竖线),首先入栈操作首先会sp(依靠偏移地址来寻址)减偏移地址,为什么是减,因为压栈的元素是压栈到栈底,下面是高地址!
2、Pop操作,原理相同,出栈操作,就是把里面的数据从上往外拿,后进先出嘛,所以空间是指针是来下面移动的(这个好像,那个纸画一画就出来了),sp就要+2,正好与压栈相反。
当然这些操作都要认为的去边界定义和代码中做一些处理机制。
注意:任意时刻,ss:sp都是指向栈顶(栈底只是我们想象出的一个栈段,其实不存在)
说了那么多关于内存中栈的知识,还是叫汇编知识吧,说一说C语言中数据结构,过程语言也好高级语言也好,其实都必须遵守后进先出的思想,才可以叫做栈,C或者高级语言就可以进行越界的限制(内存申请及条件判断等)。
技术分享图片
栈可以干些什么?可以干很多事,就拿函数每个函数调用基本都会用到栈、逆波兰、二进制转换、加密、递归等等都可以用栈数据结构方面高效的去实现。
栈的基本操作无非,初始化、压栈(Push)、出栈(Pop)、遍历栈、清空栈、销毁栈(与清空栈不是一个概念),清空栈就像欺骗内存,并非数据都给从内存清理,类似于格式化磁盘这样,让操作系统感觉这块内存没有数据,其实写入数据覆盖原来数据。
也可以分为静态栈、动态栈,怎么叫都行。用数组就是静态,用链表就是动态,不过注意:一定都要遵循后进先出的原则,否则就算写的特别灵活,出栈直接越过地位取高位,那样就违背栈的意愿,就算不上栈了!
下面是一段二进制转换代码(学习中的小练题很有意思,分享给大家),基本栈操作就不分享了,大家代码大同小异,网上有更多前辈写的高质量代码值得大家参考

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define STACK_INIT_SIZE 20
#define STACKINCREMENT 0

typedef char ElemType;
typedef struct 
{
    ElemType *top;
    ElemType *bottom;
    int stackSize;
}sqStack;

void Init_stack(sqStack *s);
void Push_stack(sqStack *s, ElemType e);
void Pop(sqStack *s, ElemType *e);
int StackLength(sqStack s);

int main(void)
{
    ElemType c;
    sqStack s;
    int len, i, sum = 0;

    Init_stack(&s);

    printf("请输入二进制数,输入#符号表示结束!\n");
    scanf("%c", &c);
    while ( c != ‘#‘ )
    {
        Push_stack(&s, c);
        scanf("%c", &c);
    }

    getchar();

    len = StackLength(s);
    printf("栈的当前容量是: %d\n",len);

    for(i = 0; i < len; i++)
    {
        Pop(&s, &c);
        sum = sum + (c-48) * pow(2, i);
    }

    printf("二进制转换10进制之后数值: %d\n",sum);

    return 0;
}

void Init_stack(sqStack *s)
{
    s->bottom = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
    if( !s->bottom )
    {
        exit(-1);
    }

    s->top = s->bottom;
    s->stackSize = STACK_INIT_SIZE;         //最大容量
}

void Push_stack(sqStack *s, ElemType e)
{
    if( s->top - s->bottom >= s->stackSize )
    {
        s->bottom = (ElemType *)realloc(s->bottom, (s->stackSize + STACKINCREMENT) * sizeof(ElemType));
        if( !s->bottom )
        {
            exit(-1);
        }
    }

    *(s->top) = e;
    s->top++;
}

void Pop(sqStack *s, ElemType *e)
{
    if( s->top == s->bottom )
    {
        return;
    }

    *e = *--(s->top);
}

int StackLength(sqStack s)
{
    return (s.top - s.bottom);

}

思想才是王道,语言是用来实现思想的价值,一体一用。

栈导论

标签:str   type   高效   思想   清理   ast   int   RoCE   必须   

原文地址:http://blog.51cto.com/13352079/2132971

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!