目录
栈
思路:后进先出,可以想象成子弹,车厢装东西等,其本质是受限制的线性表,只允许从一端操作
静态分配栈:
#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是形参,更改形参的指向对实参没有影响
不能返回局部变量的地址