1.栈的基本概念
栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。
2.相关概念
1)栈顶和栈底:允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom)
特点:栈底固定,而栈顶浮动。
2)进栈: 插入一般称为进栈(PUSH),或是入栈、压栈。
3)出栈:删除元素一般称为出栈(POP)。
特点:先进后出。
3.形象化表示
形象表示事物:杯子,水桶等。
4.相关代码实现
1)建立空栈,此时栈顶与栈底指向同一个元素。注意:不可出现野指针(垃圾值)需要制空。
void init (PSTACK pS){
pS->pTop = (PNODE)malloc(sizeof(NODE));
if(pS->pTop==NULL){
printf("动态分配内存失败!\n");
exit(-1);
}else{
pS->pBottom = pS->pTop;
pS->pTop->pNext = NULL;
}
}
2)入栈,注意pTop永远是指向最上方的位置!注意链表赋值从后往前赋值,避免找不到指向的情况出现
void push(PSTACK pS,int val){
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
pNew->pNext = pS->pTop;
pS->pTop = pNew;
return;
}
3)出栈
注意事项:必须创建一个新的节点对象,若写成pS->pTop = pS->pTop->pNext; 会造成内存泄漏,原来的Top结点找不到了并且也尚未将其释放掉。
//pS指向的栈出栈一次,把出栈元素存入至pVal中,如果失败false 成功true
bool pop(PSTACK pS, int *pval){
//这里注意empty函数中的参数应该是 栈的地址,而此时,pS已经是地址所以不能写成&pS了
if(empty(pS)){
return false;
}else{
//必须创建一个新的节点对象,若写成pS->pTop = pS->pTop->pNext; 会造成内存泄漏,原来的Top结点找不到了并且也尚未将其释放掉
PNODE r = pS->pTop;
*pVal = r->data;
pS->pTop = r->pNext;
free(r);
r = NULL;
return true;
}
}
4)遍历栈
void traverse(PSTACK pS){
PNODE p = pS->pTop;
while(p != pS->pBottom){
printf("%d",p->data);
//这里需要注意的是 栈的指向是从Top一致往下指向,直到Bottom
p = p->pNext;
}
}
5)判断是否为空
bool empty(PSTACK pS){
if(pS->pBottom==pS->pTop){
return true;
}else{
return false;
}
}
6)清栈,这里多加了一个q结点是为了避免将p = p->pNext后找不到上一结点导致内存泄漏,建议画图加深理解
//清空
void clear(PSTACK pS){
if(empty(pS)){
return;
}else{
PNODE p = pS->pTop;
PNODE q = NULL;
while(pS->pTop != pS->pBottom){
q = p->pNext;
free(q);
p = q;
}
pS->pTop = pS->pBottom;
}
}
完整版代码
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef struct Node{
int data;
struct Node *pNext;
}NODE,*PNODE;
typedef struct Stack{
PNODE pTop;
PNODE pBottom;
}STACK,*PSTACK;
void init(PSTACK pS);
void push(PSTACK pS, int val);
void traverse(PSTACK pS);
bool pop(PSTACK pS,int *pVal);
void clear(PSTACK pS);
int main(void){
STACK S;//STACK 等价于 struct Stack
int val;
//初始化
init(&S);//建立一个空栈
push(&S,1); //压栈
push(&S,2);
//遍历
traverse(&S);
pop(&S,&val);
clear(&S);
traverse(&S);
return 0;
}
void init (PSTACK pS){
pS->pTop = (PNODE)malloc(sizeof(NODE));
if(pS->pTop==NULL){
printf("动态分配内存失败!\n");
exit(-1);
}else{
pS->pBottom = pS->pTop;
pS->pTop->pNext = NULL;
}
}
void push(PSTACK pS,int val){
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
pNew->pNext = pS->pTop;
pS->pTop = pNew;
return;
}
void traverse(PSTACK pS){
PNODE p = pS->pTop;
while(p != pS->pBottom){
printf("%d",p->data);
//这里需要注意的是 栈的指向是从Top一致往下指向,直到Bottom
p = p->pNext;
}
}
bool empty(PSTACK pS){
if(pS->pBottom==pS->pTop){
return true;
}else{
return false;
}
}
//pS指向的栈出栈一次,把出栈元素存入至pVal中,如果失败false 成功true
bool pop(PSTACK pS, int *pVal){
//这里注意empty函数中的参数应该是 栈的地址,而此时,pS已经是地址所以不能写成&pS了
if(empty(pS)){
return false;
}else{
//必须创建一个新的节点对象,若写成pS->pTop = pS->pTop->pNext; 会造成内存泄漏,原来的Top结点找不到了并且也尚未将其释放掉
PNODE r = pS->pTop;
*pVal = r->data;
pS->pTop = r->pNext;
free(r);
r = NULL;
return true;
}
}
//清空
void clear(PSTACK pS){
if(empty(pS)){
return;
}else{
PNODE p = pS->pTop;
PNODE q = NULL;
while(p != pS->pBottom){
q = p->pNext;
free(q);
p = q;
}
pS->pTop = pS->pBottom;
}
}
还有些不足的地方,我会继续修改补充的。
最后:只要开始永远不晚,加油吧!你我都还年轻~