Linux笔记 --- 栈

我们可以通过顺序存储的方式来实现栈逻辑,这种栈叫做顺序栈,也可以通过链式存储的方式实现,这种栈叫做链式栈,存储结构的异同不影响栈先进后出的特性

顺序栈

顺序栈的实现主要就是定义一块连续内存存放栈元素,为了方便管理创建一个整形数据代表栈顶元素在此连续内存中的偏移,这样可以很方便的知道此栈的状态和栈顶元素位置,便于压栈和出栈,我们将这些元素存放在同一个管理结构体中,根据我们的思路,顺序栈可以用以下代码来表示:

cpp 复制代码
struct sequent_stack
{
    int *stack; //指向用以存放栈元素的连续内存
    int size;   //保存该数据栈的总大小
    int top;    //表示栈顶元素的偏移量
};

初始化

有了结构体我们就要考虑该如何初始化这个栈,首先将stack指向的内存清零,其次将top置为-1并规定-1为空栈,这么做的好处是,压栈第一个元素后top+1就成了0,第一个元素偏移为0

cpp 复制代码
struct sequent_stack *stack_init(int size)
{
    struct sequent_stack *s;
    s = malloc(sizeof(struct sequent_stack));

    if(s != NULL)
    {
        s->stack = calloc(size,sizeof(int));    
        //CALLOC函数相比于malloc的区别在于会在分配之后将内存设置为0
        s->size = size;
        s->top = -1;
    }
    return s;
}

有了初始化的栈,接下来就是编写一些基本操作

压栈

压栈的第一步要判断栈是否已满,如果未满则将元素置于栈顶,已满则进行扩充或者错误退出:

cpp 复制代码
bool stack_full(struct sequent_stack *s)
{
    return s->top >= s->size-1;
}

bool push(struct sequent_stack *s,int data)
{
    if(stack_full(s))
    return false;

    s->top++;
    s->stack[s->top] = data;
    return true;
}

出栈

出栈中因为要返回bool值表示是否成功,所以要获取一个参数来存放出栈的元素,其次在出栈前要先判断是否为空栈

cpp 复制代码
bool stack_empty(struct sequent_stack *s)
{
    return s->top == -1;
}

bool pop(struct sequent_stack *s,int *p)
{
    if(stack_empty(s))
        return false;
    
    *p = s->stack[s->top];
    s->top--;

    return true;
}

结合上面的操作我们可以使用栈操作进行十进制转8进制的操作

cpp 复制代码
int main(int argc, char const *argv[])
{
    struct sequent_stack *s;
    s = stack_init(10);

    int n;
    scanf("%d",&n);

    while(n>0)
    {
        push(s,n%8);
        n /= 8;
    }

    int m;
    while(!stack_empty(s))
    {
        pop(s,&m);
        printf("%d",m);
    }

    printf("\n");

    return 0;
}

链式栈

对于链式栈来说以上那些基本操作也是需要实现的,由此我们进行

初始化

首先定义管理结构体和节点结构体

cpp 复制代码
struct node //栈节点结构体
{
    int data;
    struct node *next;
};

struct linked_stack //管理结构体
{
    int size;
    struct node *top;   //指向栈顶节点
};

再根据管理结构体进行初始化

cpp 复制代码
struct linked_stack *init_stack (void)
{
    struct linked_stack *s;
    s = malloc(sizeof(struct linked_stack));

    if(s != NULL)
    {
        s->size = 0;
        s->top = NULL;
    }

    return s;
}

压栈

cpp 复制代码
//创建新节点
struct node *new_node(int data)
{
    struct node *new;
    new = malloc(sizeof(struct node));

    if(s != NULL)
    {
        new->data = data;
        new->next = NULL;
    }

    return new;
}

//压栈
bool push(struct linked_stack *s,struct node *new)
{
    if (s == NULL || new == NULL)
        return false;
    
    new->next = s->top;
    s->top = new;
    s->size++;

    return true;
}

出栈

cpp 复制代码
bool stack_empty(struct linked_stack *s)
{
    return s->size == 0;
}

bool pop(struct linked_stack *s,int *p)
{
    if(s == NULL || p == NULL || stack_empty(s))
        return false;

    *p = s->top->data;
    s->top = s->top->next;
    s->size--;

    return true;
}

汉诺塔

根据链栈,写出一个汉诺塔问题的递归函数

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

struct node //栈节点结构体
{
    int data;
    struct node *next;
};

struct linked_stack //管理结构体
{
    int size;
    struct node *top;   //指向栈顶节点
};

struct linked_stack *init_stack (void)
{
    struct linked_stack *s;
    s = malloc(sizeof(struct linked_stack));

    if(s != NULL)
    {
        s->size = 0;
        s->top = NULL;
    }

    return s;
}

//创建新节点
struct node *new_node(int data)
{
    struct node *new;
    new = malloc(sizeof(struct node));

    if(new != NULL)
    {
        new->data = data;
        new->next = NULL;
    }

    return new;
}

//压栈
bool push(struct linked_stack *s,struct node *new)
{
    if (s == NULL || new == NULL)
        return false;
    
    new->next = s->top;
    s->top = new;
    s->size++;

    return true;
}

bool stack_empty(struct linked_stack *s)
{
    return s->size == 0;
}

bool pop(struct linked_stack *s,struct node **p)
{
    if(s == NULL || p == NULL || stack_empty(s))
        return false;

    *p = s->top;
    s->top = s->top->next;
    (*p)->next = NULL;
    s->size--;

    return true;
}

void show(struct linked_stack *A,struct linked_stack *B,struct linked_stack *C)
{
    int maxlen,len;

    maxlen = A->size > B->size ? A->size : B->size;
    maxlen = maxlen > C->size ? maxlen : C->size;
    len = maxlen;

    struct node *t1 = A->top;
    struct node *t2 = B->top;
    struct node *t3 = C->top;

    int i;
    for (i = 0; i < maxlen; i++)
    {
        if(t1 != NULL && len <= A->size)
        {
            printf("%d",t1->data);
            t1 = t1->next;
        }
        printf("\t");

        if(t2 != NULL && len <= B->size)
        {
            printf("%d",t2->data);
            t2 = t2->next;
        }
        printf("\t");

        if(t3 != NULL && len <= C->size)
        {
            printf("%d",t3->data);
            t3 = t3->next;
        }
        printf("\t");

        printf("\n");
        len--;
    }
    printf("A\tB\tC\n");
    printf("-----------------\n");
}

void hano(struct linked_stack *A,struct linked_stack *B,struct linked_stack *C,int n)
{
    if(n <= 0)
        return;
    
    struct node *tmp;
    hano(A,C,B,n-1);    //将n-1块从A借助C移向B

    getchar();          //每回车一次进行一步
    show(A,B,C);

    pop(A,&tmp);
    push(C,tmp);        //将A最下面一块移动到C

    hano(B,A,C,n-1);    //将n-1块从B借助A移向C
}

int main(int argc, char const *argv[])
{
    struct linked_stack *A = init_stack();
    struct linked_stack *B = init_stack();
    struct linked_stack *C = init_stack();

    int hanois = 0;
    scanf("%d",&hanois);

    int i;
    for (i = 0; i < hanois; i++)
    {
        struct node *new = new_node(hanois-i);  //将汉诺塔中的块放入栈A(柱A)
        push(A,new);
    }
    
    hano(A,B,C,hanois);

    show(A,B,C);

    return 0;
}
相关推荐
数据小爬虫@14 分钟前
如何高效利用Python爬虫按关键字搜索苏宁商品
开发语言·爬虫·python
ZJ_.16 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
Narutolxy21 分钟前
深入探讨 Go 中的高级表单验证与翻译:Gin 与 Validator 的实践之道20241223
开发语言·golang·gin
Hello.Reader29 分钟前
全面解析 Golang Gin 框架
开发语言·golang·gin
禁默39 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Code哈哈笑1 小时前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
gb42152871 小时前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
程序猿进阶1 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
qq_433618441 小时前
shell 编程(二)
开发语言·bash·shell