概念
栈的定义
栈是一种只能在一端进行插入或删除操作的线性表。其中允许进行插入或删除操作的一端称为栈顶(Top)。
栈顶由一个称为栈顶指针的位置指示器(其实就是一个变量,对于顺序栈,就是记录栈顶元素所在数组位置标号的一个整型变量;
对于链式栈,就是记录栈顶元素所在结点地址的指针)来指示,它是动态变化的。
表的另一端称为栈底,栈底是固定不变的。
栈的插入和删除操作一般称为入栈和出栈。
栈的特点
由栈的定义可以看出,栈的主要特点就是先进后出(FILO)。栈中的元素就好比开进一个死胡同的车队,最先开进去的汽车只能等后进来的汽车都出去了,才能出来。
栈的存储结构
可用顺序表和链表来存储栈,栈可以依照存储结构分为两种:顺序栈和链式栈。在栈的定义中已经说明,栈是一种在操作上稍加限制的线性表,即栈本质上是线性表,而线性表有两种主要的存储结构——顺序表和链表,因此栈也同样有对应的两种存储结构。
栈的数学性质
当n个元素以某种顺序进栈,并且可在任意时刻出栈(在满足先进后出的前提下)时,所获得的元素排列的数目N恰好满足函数 Catalan()的计算,即
链栈的两个状态:
(1)栈空状态:stack->next==NULL。即没有开始结点。
(2)栈满状态:理论上不存在栈满的情况。
链栈的两个操作:
(1)(由指针p所指的元素)进栈操作
p->next=stack->next;
stack->next=p;
(2)出栈操作(出栈元素保存在x中)
p=stack->next;
x=p->data;
stack->next=p->next;
free(p);
代码
#include <stdio.h>
#include <stdlib.h>
#define maxSize 20
/* 链栈结点定义 */
typedef struct LNode {
int data; // 数据域
struct LNode *next;// 指针域
} LNode;
/* 初始化栈 */
/* *&list指的是要初始化的栈 */
void initStack(LNode *&list) { // list要改变,所以要用引用型
/* list表示头结点,list->data没有值,list->next表示栈顶结点 */
list=(LNode *)malloc(sizeof(LNode));// 制造一个头结点
list->next=NULL;
}
/* 判断是否栈空,如果栈空返回1,否则返回0 */
/* *list指的是要进行判断的链栈 */
int isEmpty(LNode *list) {
if(list->next==NULL) { // 栈空状态:list->next==NULL
return 1;
} else {
return 0;
}
}
/* 入栈 */
/* *list指的是要入栈操作的链栈;x指的是要新入栈的元素的data值 */
void push(LNode *list,int x) {
/* 申请新的进栈结点 */
LNode *newNode;
newNode=(LNode *)malloc(sizeof(LNode));
newNode->next=NULL;
/* 将新结点入栈,也是链表的头插法 */
newNode->data=x;// 为新结点赋予数据
newNode->next=list->next;
list->next=newNode;
}
/* 出栈 */
/* *list指的是要出栈的链栈;&x指的是出栈元素的data值 */
int pop(LNode *list,int &x) {
LNode *temp=list->next;// 开始结点,也就是要出栈的结点
if(temp==NULL) {
return 0;
} else {
list->next=temp->next;// 将头结点的next指向被删除结点(出栈结点)的next
x=temp->data;// 保存出栈结点的数据data
free(temp);// 是否结点资源
return 1;// 出栈成功返回1
}
}
/* 打印链栈 */
/* list指的是要被打印的链栈 */
void printStack(LNode *list) {
LNode *temp=list->next;
printf("\n");
while(temp!=NULL) {
printf("%d\t",temp->data);
temp=temp->next;
}
printf("\n");
}
int main() {
LNode *list;
int x;
initStack(list);// 初始化栈
/* 入栈 */
push(list,1);// 将1入栈
push(list,2);// 将2入栈
push(list,3);// 将3入栈
push(list,4);// 将4入栈
push(list,5);// 将5入栈
printStack(list);// 打印入栈成功的链栈
/* 判断栈空 */
printf("是否栈空(1表示栈空,0表示非空):%d\n",isEmpty(list));
/* 出栈 */
/* 第一次出栈 */
pop(list,x);// 将栈顶元素出栈
printf("出栈元素:%d",x);// 打印出栈的元素
printStack(list);// 打印剩下的链栈元素
/* 第二次出栈 */
pop(list,x);// 将栈顶元素出栈
printf("出栈元素:%d",x);// 打印出栈的元素
printStack(list);// 打印剩下的链栈元素
/* 第三次出栈 */
pop(list,x);// 将栈顶元素出栈
printf("出栈元素:%d",x);// 打印出栈的元素
printStack(list);// 打印剩下的链栈元素
return 0;
}
测试结果如下: