数据结构--链式栈、顺序栈的基本实现与简单应用:进制转换
来源:互联网 发布:mac开机按option选恢复 编辑:程序博客网 时间:2024/05/19 13:20
一、栈的基本概念:
1、栈(Stack),是基本数据结构中比较重要的一种,其遵循的基本原则是:先进后出(First In Last Out,FILO);我们编程时操作系统为函数参数压栈,其系统内核栈的实现就是基于该数据结构。我们以顺序栈来介绍起基本结构。下图为一个基本的栈的结构(这是一个顺序栈):
我们所建的栈以及内核中实现,在结构上其实并非该图所示,因为内存地址从高到低分配,所以栈应该是“口朝下”的,但是为了方便理解(现实中我们认为“底”应该在下面)所以我们用这种图来表示。栈有两个指针来标识其“头”与“尾”,其中,栈的高地址指针叫栈底指针(pBottom),栈的低地址指针叫做栈顶指针(pTop)。数据存入栈中称为数据入栈(或者压栈),数据从栈中取出来称为出栈(或者推栈)。在该图中,入栈的顺序是num1->num2->num3->num4,而出栈顺序是num4->num3->num2->num1;最先入栈的数据最后才能被推栈出来,所以叫先入后出式存储结构。
2、关于栈的口朝下还是口朝上问题,我们用一个小例子来测试一下:
# include<stdio.h>int add(int x,int y)/*函数传参压栈顺序为从右向左*/{ printf("address_x = %p\naddress_y = %p\n",&x,&y); return (x+y);}int main(void){ int sum = add(3,5); printf("sum = %d\n",sum);}
我们将x和y的地址打印输出:
由于y先压栈,x后压栈,我们打印输出的结果显示,address_y为高地址,而address_x为低地址,所以由此我们可以得出,操作系统在栈的实现中是高地址为栈底,低地址为栈顶。因此我们还是将栈的结构图再翻过来吧:
3、满“栈”与空“栈”,听到这两个名字,也许你会认为,“满栈”就是栈已经存满了数据,而“空栈”则是栈中没有数据,那你就大错特错了。首先,我们画出两张栈的结构图:
在该图中,我们发现满栈与空栈中都没有存放数据,但是满栈pTop指针并没有指向第一块栈内存,而空栈的pTop指针指向了第一块栈内存。所以,这就是满栈与空栈的区别:
满栈:满栈的栈顶指针指向栈顶数据(没有数据时,和pBottom都指向NULL),对于满栈的操作则是,先移动栈顶指针,然后在栈顶指针所指向的内存中存入数据;
空栈:空栈的栈顶指针指向一块空内存(没有数据时,pBottom指向NULL,pTop不指向NULL),该内存的上一块内存才是最顶层的数据,对于空栈的操作则是,先在栈顶指针所指向的内存中存入数据,然后移动栈顶指针;
今天我们采用满栈来进行一系列操作。
二、顺序栈(借助数组)的实现与操作:
# include <stdio.h># include <stdlib.h># include <string.h># define MAX_STACK_LEN 5 /*栈最大元素个数*//*顺序栈的结构体定义*/typedef struct stack_arr{ int data[MAX_STACK_LEN]; int top;//数组下标作为栈顶指针,而栈底指针不需要指定}STACKARR;void init_stack(STACKARR *);//初始化栈int empty_stack(STACKARR * pS);//栈判空int full_stack(STACKARR * pS);//栈判满void push_stack(STACKARR *);//压栈void traverse_stack(STACKARR *);//遍历void pop_stack(STACKARR *);//出栈void clear_stack(STACKARR * pS);//栈清空int main(void){ STACKARR Stack;/*创建了一个含有MAX_STACK_LEN个数据的顺序栈*/ init_stack(&Stack);/*对该栈初始化*/ push_stack(&Stack); printf("压栈完毕,栈中元素依次为(栈顶->栈底):\n"); traverse_stack(&Stack); pop_stack(&Stack); printf("出栈完毕,栈中元素依次为(栈顶->栈底):\n"); traverse_stack(&Stack); clear_stack(&Stack); printf("栈已清空"); traverse_stack(&Stack); return 0;}void init_stack(STACKARR * pS){ memset(pS->data, 0, sizeof(pS->data)); pS->top = -1;/*满栈让栈定指针初始化在第一个地址的前一个地址*/}int empty_stack(STACKARR * pS){ return ( (pS->top == - 1) ? (-1) : (0) );}int full_stack(STACKARR * pS){ return ( (pS->top == MAX_STACK_LEN - 1) ? (-1) : (0) );}void push_stack(STACKARR * pS){ int num = 0; int choose = 0; while(1){ if(full_stack(pS) == -1){ printf("栈已满,不能压栈!\n"); exit(EXIT_FAILURE); } printf("请输入要压栈的数据:"); scanf("%d",&num); pS->top++;/*满栈先移动指针,再存储*/ pS->data[pS->top] = num; printf("入栈成功,继续入栈?(继续输入1,结束输入2):"); scanf("%d",&choose); if(choose != 1){ break; } }}void traverse_stack(STACKARR * pS){ int i = 0; if(empty_stack(pS) == -1){ printf("栈为空!\n"); exit(EXIT_FAILURE); } /*从栈顶部开始遍历*/ for(i = pS->top; i >= 0; i-- ){ printf("%d\t",pS->data[i]); } printf("\n");}void pop_stack(STACKARR * pS){ int choose = 0; while(1){ if(empty_stack(pS) == -1){ printf("栈为空!\n"); exit(EXIT_FAILURE); } printf("出栈元素为:%d\n",pS->data[pS->top]);/*先出栈栈顶指针再自减1*/ pS->top--; printf("出栈成功,继续出栈?(继续输入1,结束输入2):"); scanf("%d",&choose); if(choose != 1){ break; } }}void clear_stack(STACKARR * pS){ memset(pS->data, 0, sizeof(pS->data)); pS->top = -1;}
测试结果:
三、链式栈(借助链表)的实现与操作:
我们今天使用双向链表来实现(单向链表更简单,但是双向链表的复杂会使我们对栈这种结构认识更加清晰),基本结构如下:
测试代码:
/** *2016年12月13日10:52:39 *Create Stack of Link**/#include <stdio.h>#include <stdlib.h>#ifndef bool#define bool inttypedef struct stack_node{ int data; struct stack_node * pDown; struct stack_node * pUp;}STACKNODE;/*栈的节点结构体*/typedef struct stack_link{ STACKNODE * pTop; STACKNODE * pBottom;}STACKLINK; /*栈顶指针与栈底指针结构体*/enum{false,true};void init_stack(STACKLINK *);/*初始化*/void push_stack(STACKLINK *);/*压栈*/void travsal_stack(STACKLINK *);/*遍历*/void pop_stack(STACKLINK *);/*出栈*/bool empty_stack(STACKNODE * pS);/*栈判空,链式栈不存在满栈情况,无需判满*/int main(void){ STACKLINK Stack; init_stack(&Stack);/*初始化栈*/ push_stack(&Stack);/*压栈*/ travsal_stack(&Stack);/*从栈顶开始遍历*/ pop_stack(&Stack);/*出栈*/ travsal_stack(&Stack); return 0;}void init_stack(STACKLINK * pS){ pS->pTop = NULL; pS->pBottom = NULL;/*初始化将栈顶指针与栈底指针均赋空*/ printf("初始化成功!\n");}void push_stack(STACKLINK * pS){ int num, choose; STACKNODE * pNew = NULL; while(1){ printf("请输入压栈数据:"); scanf("%d",&num); pNew = (STACKNODE *)malloc(sizeof(STACKNODE)); if(NULL == pNew){ printf("内存分配失败!\n"); exit(EXIT_FAILURE); } pNew->data = num; pNew->pUp = NULL; pNew->pDown = NULL;/*入栈元素初始化*/ if(empty_stack(pS->pTop) == -1){/*栈为空*/ pS->pBottom = pS->pTop = pNew; } else{/*栈不为空*/ pS->pTop->pUp = pNew;/*上一个为新元素*/ pNew->pDown = pS->pTop;/*新元素的下一个为原有栈顶元素*/ pS->pTop = pNew;/*栈顶指针向上移到*/ } printf("继续压栈?(继续请选1,结束请选2):"); scanf("%d",&choose); if(choose != 1){ break; } }}void travsal_stack(STACKLINK * pS){ STACKNODE * pMove; pMove = pS->pTop; while(1){ if(pMove == NULL){ break; } printf("%d\t",pMove->data); pMove = pMove->pDown; } printf("\n");}void pop_stack(STACKLINK * pS){ STACKNODE * pDelete; int choose = 0; while(1){ pDelete = pS->pTop; if(empty_stack(pDelete) == -1){ printf("栈为空,出栈失败!\n"); exit(EXIT_FAILURE); } printf("出栈元素为:%d\n",pDelete->data); pS->pTop = pDelete->pDown;/*栈顶指针向下移*/ if(pS->pTop != NULL)/*注意当pS->pTop为空,即栈为空时,无pS->pTop->pUp,若不判断会出现段错误*/ pS->pTop->pUp = NULL;/*栈顶指针的上一个(前驱指针)为空*/ free(pDelete); printf("继续出栈?(继续请选1,结束请选2):"); scanf("%d",&choose); if(choose != 1){ break; } }}bool empty_stack(STACKNODE * pN){ return ((pN == NULL) ? -1 : 0);}#endif
四、栈的应用——借助栈实现进制转换:
/*用数组创建一个栈*/# include<stdio.h># include<string.h># include<stdlib.h># define SIZE 32typedef struct Stack{ int sta_arr[SIZE]; int top;}STACK;void init_stack(STACK *);void init_stack(STACK * pS){ memset(pS->sta_arr, 0, sizeof(pS->sta_arr)); pS->top = -1;}int is_full(STACK * pS){ return ((pS->top == SIZE-1) ? 0 : 1);}int is_empty(STACK * pS){ return ((pS->top == -1) ? 0 : 1);}void input_stack(STACK * pS, int value){ if(is_full(pS)){ pS->top++; pS->sta_arr[pS->top] = value; }}void output_stack(STACK * pS){ if(is_empty(pS)) printf("%d",(pS->sta_arr)[pS->top]);}void invert(STACK * pS, int value, int type){ int tmp,num = value; init_stack(pS); while(num) { /*进制转化:取余之后压栈,再取整,低位就在栈底,自然最后输出*/ tmp = num % type; input_stack(pS,tmp); num = num / type; } /*出栈*/ while(pS->top != -1) { output_stack(pS); pS->top--; } printf("\n");}int main (void){ STACK S; int value, type; init_stack(&S); printf("请输入你要转换的十进制数字:\n"); scanf("%d",&value); printf("请选择你要转换成的进制格式(2~9,如:2代表二进制):\n"); scanf("%d",&type); if(type > 9 || type < 2){ printf("选择的进制格式暂时无法处理!\n"); exit(EXIT_FAILURE); } invert(&S,value,type); return 0;}
测试:
- 数据结构--链式栈、顺序栈的基本实现与简单应用:进制转换
- 顺序栈与链式栈的实现
- 重温数据结构:栈的顺序表示和实现与栈的链式表示和实现
- 链式栈的基本操作与实现
- 数据结构之链式栈的应用-简单表达式计算
- 数据结构-链式栈的实现
- 数据结构---栈的链式实现
- 数据结构-->栈的链式实现
- 栈的基本应用-数制转换-数据结构
- 简单数据结构的实现之顺序栈
- 数据结构之链式队列与链式栈的应用-球钟问题
- 数据结构与算法设计---链式栈的实现(C++)
- 数据结构基础(13) --链式栈的设计与实现
- 企业级数据结构-栈的链式存储设计与实现
- 数据结构基础(13) --链式栈的设计与实现
- 数据结构基础(13) --链式栈的设计与实现
- 数据结构---C语言栈的链式表示与实现
- 链式栈 (实现进制转换)
- Android AIDL demo (Android Studio)
- 漫步凸分析十一——分离定理
- 变量与常量的区别、接口的特性
- 约瑟夫环
- python文件命名小脚本
- 数据结构--链式栈、顺序栈的基本实现与简单应用:进制转换
- [LeetCode463]Island Perimeter
- documnet.forms[]数组
- 我决定写博客了
- JQueryValidationEngine常见问题
- 【JAVA秒会技术之多线程】彻底理解ThreadLocal
- Android反翻译详解
- 【树】哈夫曼树(二)
- 构建语言模型(一):文本语料处理