数据结构之静、动态栈对数据的相关运算及其特征

目录

链式栈:

总结:


 

思路:后进先出,可以想象成子弹,车厢装东西等,其本质是受限制的线性表,只允许从一端操作

静态分配栈

#define MAXLEN 100
typedef	struct data{
		int top;//栈顶
		int data[MAXLEN];//数组存放数据
}Seqstack,*pSeqstack;

缺点:一旦声明好,栈的空间固定,不灵活

静态动态分配栈

typedef int TypeData;
typedef	struct data{
		int top;//栈顶
		TypeData *data;//数组首地址
		int maxlen;//最大长度
}Seqstack, *pSeqstack;

_SEQSTACK_H_:

#ifndef _SEQSTACK_H_
#define _SEQSTACK_H_
#include <stdio.h>
#include <stdlib.h>

typedef int type;
typedef struct data{
    type *data;
    int maxlen,top;
}Seqstack,*pSeqstack;
//用传参的方式初始化栈
int stack_create(pSeqstack *S,int maxlen);
//栈判空
int stack_empty(pSeqstack s);
//栈判满 
int stack_full(pSeqstack s);
//进栈
type stack_push(pSeqstack s,type data);
//弹栈(清空栈在顺序栈中也是一个一个出栈)
type stack_pop(pSeqstack s,type *data);
//展示栈
int stack_show(pSeqstack s);
//释放栈
int stack_destory(pSeqstack *S);
//取栈顶元素 
type stack_get_top(pSeqstack s);

#endif

seqstack.c

#include "seqstack.h"

//用传参的方式创建并初始化栈
int stack_create(pSeqstack *S,int maxlen)
{
    *S = malloc(sizeof(Seqstack));
    if(NULL == *S){
        perror("stack_malloc");
        return -1;
    }
    (*S)->data = malloc(maxlen*sizeof(type));
    if(NULL == (*S)->data){
        perror("data_malloc");
        free(*S);//数组空间未创建成功,删除已经创建的栈
        *S = NULL;
        return -1;
    }
    (*S)->top = -1;//栈类似数组下标0开始
    (*S)->maxlen = maxlen;
    return 0;
}
//栈判空
int stack_empty(pSeqstack s)
{
    if(NULL == s)
        return -1;
    if(-1 == s->top)
        return 0;
    return -1;
}
//栈判满 
int stack_full(pSeqstack s)
{
    if(NULL == s)
        return -1;
    if(s->maxlen-1 == s->top)//例如:9为0~8
        return 0;
    return -1;
}
//进栈
type stack_push(pSeqstack s,type data)
{
    if(NULL==s || 0==stack_full(s))
        return -1;
    s->top++;//要存数据下标先加1 
    s->data[s->top] = data;
    return 0;
}
//弹栈(清空栈在顺序栈中也是一个一个出栈)
type stack_pop(pSeqstack s,type *data)
{
    if(NULL==s || 0==stack_empty(s))
        return -1;
//若输入的data是NULL,则代表用户不需要保存栈顶元素
    if(NULL != data){
        //暂存即出栈但不弹栈 NULL(暂存在栈中)
        *data = s->data[s->top];
        return *data;
    }
    s->top--;
    return 0;
}
//展示栈
int stack_show(pSeqstack s)
{
    if(NULL==s || 0==stack_empty(s))
        return -1;
    int flag = s->top;//设置标志位防止栈顶下标移动
    while(-1 != flag){//只展示不移动
        printf("%d ",s->data[flag--]);
    }
    puts("");
    return 0;
}
//释放栈
int stack_destory(pSeqstack *S)
{
    if(NULL == *S)
        return -1;
    free((*S)->data);
    free(*S);
    *S = NULL;
    return 0;
}
//取栈顶元素 
type stack_get_top(pSeqstack s)
{
    if(NULL==s || 0==stack_empty(s))
        return -1;
    return s->data[s->top];
}

main.c

#include "seqstack.h"

int stack_create(pSeqstack *S,int maxlen);
int stack_empty(pSeqstack s);
int stack_full(pSeqstack s);
type stack_push(pSeqstack s,type data);
type stack_pop(pSeqstack s,type *data);
int stack_show(pSeqstack s);
int stack_destory(pSeqstack *S);
type stack_get_top(pSeqstack s);
int main(int argc, char *argv[])
{ 
    pSeqstack p = NULL;
    stack_create(&p,10);
    type data;
    while(1){
        printf("please input push data :");
        if(0 == scanf("%d",&data)){
            getchar();
            break;
        }
        stack_push(p,data);
    }
    stack_show(p);
    printf("%d\n",stack_pop(p,&data));
    stack_show(p);
    stack_pop(p,NULL);
    stack_show(p);
    stack_destory(&p);
    if(NULL == p){
        fputs("p is NULL\n",stdout);
    }
    return 0;
} 

makefile:

all:
	gcc ./src/*.c -o stack -I ./inc/
clean:
	rm stack

结果

root@ubuntu:/mnt/U_share/DATA/stack/seqstack# ls
inc  makefile  src  stack
root@ubuntu:/mnt/U_share/DATA/stack/seqstack# make
gcc ./src/*.c -o stack -I ./inc/
root@ubuntu:/mnt/U_share/DATA/stack/seqstack# ./stack 
please input push data :1
please input push data :1
please input push data :2
please input push data :3
please input push data :3
please input push data :4
please input push data :q
4 3 3 2 1 1 
4
4 3 3 2 1 1 
3 3 2 1 1 
p is NULL

改进:可以用传参的方法让用户自己定义大小,但还是一旦声明好便不会再改变(共享栈)

总结:开辟结构体,开辟数组
free()表示这个是标记的无主的,可以随便使用
*L = NULL;减少乱码率
scanf()正确录入和错误录入
正确录入返回0,如果有参数就返回个数
如3,2,1,0,正确录入3,2,1,0个
-l 链接库(指明路径,自己的库-L)
清空栈,释放栈;
5分钟,半小时

链式栈

存储结构为链式的栈

linkstack.h

#ifndef _LINKSTACK_H_
#define _LINKSTACK_H_
#include <stdio.h>
#include <stdlib.h>

typedef int type;
typedef struct data{
    type data;
    struct data *next;//指针域
}Linkstack,*pLinkstack;
//用传参的方式初始化栈
int stack_create(pLinkstack *S);
//栈判空
int stack_empty(pLinkstack s);
//进栈
type stack_push(pLinkstack s,type data);
//弹栈
type stack_pop(pLinkstack s,type *data);
//清空栈
int stack_clear(pLinkstack s);
//展示栈
int stack_show(pLinkstack s);
//释放栈
int stack_destory(pLinkstack *S);
//取栈顶元素
type stack_get_top(pLinkstack s);

#endif

linkstack.c

#include "linkstack.h"

//用传参的方式初始化栈
int stack_create(pLinkstack *S)
{
    *S = malloc(sizeof(Linkstack));
    if(NULL == *S){
        perror("stack_malloc");
        return -1;
    }
    (*S)->next = NULL;
    return 0;
}
//栈判空
int stack_empty(pLinkstack s)
{
    if(NULL == s)
        return -1;
    if(NULL == s->next)
        return 0;
    return -1;
}
//进栈 皆是控制同一边进出(head)
type stack_push(pLinkstack s,type data)
{
    if(NULL == s)
        return -1;
    pLinkstack p = malloc(sizeof(Linkstack));
    if(NULL == p){
        perror("data_malloc");
        return -1;
    }
    p->data = data;
    p->next = s->next;
    s->next = p;
    return 0;
}
//弹栈 皆是控制同一边进出(head)
type stack_pop(pLinkstack s,type *data)
{
    if(NULL==s || 0==stack_empty(s))
        return -1;
    pLinkstack p;
    int temp;//暂存数据的临时变量 
    if(NULL == data){
        p = s->next;
//s->data = p->data;//头结点暂存待释放结点的数据也可,因为我们规定过头结点不存放数据,是空的
        temp = p->data;//暂存待释放结点的数据域
        s->next = p->next;
        free(p);
        return temp;//返回形参给人看,已经无空间,无其他实际意义
    }else{
        p = s->next;
        *data = p->data;
        s->next = p->next;
        free(p);
        return *data;//返回一级指针,表示这指针指向的空间还有用,可进行其他操作
    }
}
//清空栈
int stack_clear(pLinkstack s)
{
    if(NULL==s || 0==stack_empty(s))
        return -1;
    //用指针 p 指向指针 s 指向的空间(替换)
    pLinkstack p = s->next,q;
    s->next = NULL;
    while(p){
        q = p;
        p = p->next;
        free(q);
    }
    return 0;
}
//展示栈
int stack_show(pLinkstack s)
{
    if(NULL==s || 0==stack_empty(s))
        return -1;
    while(s->next){
        printf("%d ",s->next->data);
        s = s->next;
    }
    puts("");
    return 0;
}
//释放栈
int stack_destory(pLinkstack *S)
{
    if(NULL == *S)
        return -1;
    stack_clear(*S);
    free(*S);
    *S = NULL;
    return 0;
}
//取栈顶元素
type stack_get_top(pLinkstack s)
{
    if(NULL==s || 0==stack_empty(s))
        return -1;
    return s->next->data;//头结点不存放数据
}

main.c:

#include "linkstack.h"

int stack_create(pLinkstack *S);
int stack_empty(pLinkstack s);
type stack_push(pLinkstack s,type data);
type stack_pop(pLinkstack s,type *data);
int stack_clear(pLinkstack s);
int stack_show(pLinkstack s);
int stack_destory(pLinkstack *S);
type stack_get_top(pLinkstack s);
int main(int argc, char *argv[])
{ 
    pLinkstack p = NULL;
    stack_create(&p);
    type data;
    while(1){
        fputs("please push stack : ",stdout);
        if(0 == scanf("%d",&data)){
            getchar();
            break;
        }
        stack_push(p,data);
    }
    stack_show(p);
    pLinkstack q = NULL;
    stack_create(&q);
    //两个栈可以构成一个队列
    while(0 != stack_empty(p)){
        stack_push(q,stack_pop(p,NULL));
    }
    stack_show(q);
    printf("top:%d\n",stack_get_top(q));
    stack_destory(&q);
    if(NULL == q)
        printf("this NULL.\n");
    return 0;
} 

结果

root@ubuntu:/mnt/U_share/DATA/stack/linkstack# make
gcc ./src/*.c -o stack -I ./inc/
root@ubuntu:/mnt/U_share/DATA/stack/linkstack# ./stack 
please push stack : 1
please push stack : 1
please push stack : 2
please push stack : 2
please push stack : 3
please push stack : 4
please push stack : 4
please push stack : q
4 4 3 2 2 1 1 
1 1 2 2 3 4 4 
top:1
this NULL.

总结

#ifndef  #define  #endif  避免重复定义、重复展开
const 和 #define的区别:作用域不一样
const定义在全局变量,局部变量可以被覆盖
define在编译阶段替换,局部变量覆盖报错

另外,头文件多了增加编译时间
我们规定头节点不存数据,如下:
typedef struct node{
        int data;
        struct node *next;
}Linkstack,*pLinkstack;
但是我们如果需要头结点存放数据,则需要两个结构体,一个结构体指向另一个结构体的头结点,从而管理这个结构体。

段错误:跟踪打印或者gdb调试、dbug调试
另外,正常情况下并没有show()这个函数,仅仅只是为了方便自己观测而已

更改s的指向,是因为s是形参,更改形参的指向对实参没有影响

不能返回局部变量的地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值