时间:2017年1月20日,15:19:06
自学于郝斌老师
栈的定义:
静态内存在栈里分配,动态内存在堆里分配。
在栈里面,系统帮你分配内存,在堆里,要自己手动分配
栈和堆表示的是分配数据的一种方式
静态的局部变量 是以压栈出栈的方式分配内存,称为 栈区
而动态的是以堆排序的方式分配内存,称为 堆区
eg:
#include <stdio.h>
#include <malloc.h>
void f(int k)
{
int m;
double *q=(double*)malloc(200);
}
int main(void)
{
int i=10;
int *p=(int *)malloc(100);
return 0;
}
其中 局部变量 i,p,m,q,k 都在栈里面分配,而100,200都在堆里分配的。
大纲:
线性结构的两种常见应用之一 栈
定义
一种可以实现“先进后出”的存储结构
栈类似于箱子
栈的分类:
静态栈(以数组方式)
动态栈(以链表方式)_重要
重点:
先进后出 的特点,删除增加数据时,从后往前。
队列,先进先出;栈,先进后出。
栈的初始化
void Init_stack(PSTACK pS)//初始化栈的关键:让栈的尾指针与头指针共同指向一个无用的节点
{ //并且还要把其节点的指针域清空
//而这个节点就是以后的尾节点,其含义就相当于单链表中的头节点
pS->pTop = (PNODE)malloc(sizeof(NODE));
pS->pBottom = pS->pTop;
pS->pBottom->pNext = NULL;
return;
}
栈的遍历
void Traverse_stack(PSTACK pS)//其关键:栈中凡是不等尾节点的节点,都是有效元素
{ //注意:不同于链表的是:头节点的元素一定要输出,因为在栈中 头节点是有效元素
//而在链表中,头节点是无实际含义的节点,其作用就是便于对链表的操作
//在链表中 在头节点之后的节点才是有效节点
//总结:栈的尾节点含义相当于链表的头节点,操作其结构时,也要相应进行改变。
PNODE p = pS->pTop;
while (p != pS->pBottom)
{
printf("%d ", p->data);
p = p->pNext;
}
printf("\n");
return;
}
判断是否空栈
bool Empty_stack(PSTACK pS)//判断空栈的关键:(也就是根据初始化栈的原理而来)头节点是否等于尾节点
{
if (pS->pTop == pS->pBottom)
return true;
else
return false;
}
求栈长度
int Length_stack(PSTACK pS)//其关键:有多少个不等于尾节点的节点 就是其栈的长度
//注意:不能擅用头指针,应该新建个局部指针代替,不然头指针位置会改变,引起未来麻烦
{
PNODE p = pS->pTop;
int len = 0;
while (p != pS->pBottom)
{
len++;
p = p->pNext;
}
return len;
}
栈的压栈
void Push_stack(PSTACK pS)//进栈的位置:尾节点与头节点共同指向节点的 后一个节点,然后以此类推
{ //元素进栈之后,栈的尾指针不变,头指针永远指向第一个元素 也就是最后一个进栈的元素
int len;
printf("输入生成节点的总个数:");
scanf("%d", &len);
for (int i = 1;i <= len;i++)
{
printf("输入第%d个节点的值:", i);
PNODE pNew = (PNODE)malloc(sizeof(NODE));
scanf("%d", &pNew->data);
pNew->pNext = pS->pTop;
pS->pTop = pNew;
}
return;
}
栈的出栈
bool Pop_stack(PSTACK pS,int *Val)//所谓出栈,就是把栈的最后一个节点移除 与删除节点方法类似
{
if (pS->pTop == pS->pBottom)
return false;
PNODE q = pS->pTop;
*Val = q->data;
pS->pTop = q->pNext;
free(q);
q = NULL
return true;
}
栈的清除
bool Clear_stack(PSTACK pS)//其原理很聪明,利用两个指针,一上接一下的清除掉各个节点。
{
if (pS->pTop == pS->pBottom)
return false;
PNODE p = pS->pTop;//p 指针为主要清除指针
PNODE q = NULL; //q 指针为其辅助,给 q 指针 指出下一个清除目标
while (p != pS->pBottom)
{
q = p->pNext;//q 指针永远指向 p指针的下一个节点!
free(p);
p = q; //每次清除节点后,p 指针又指向 q 指针,继而清除下一个节点,以此类推。
}
pS->pTop = pS->pBottom;//注意,最后 尾指针一定要等于头指针!相当于把栈 初始化!
return true;
}
栈不同于链表,不能对栈中元素进行操作,不然就不是栈了
但自己假期闲着无聊,搞了增删排序,但也是不符合栈的定义的。
栈的排序
void Sort_stack(PSTACK pS)//栈的排序与单链表的排序类似,同是利用冒泡框架,泛型算法
{
PNODE p, q;
int i, j, temp;
int len = Length(pS);
for (p=pS->pTop,i = 0;i < len - 1;i++,p=p->pNext)
{
for (q=p->pNext,j = i + 1;j < len;j++,q=q->pNext)
{
if (p->data > q->data)
{
temp = p->data;
p->data = q->data;
q->data = temp;
}
}
}
return;
}
栈的特定节点删除
bool Delete_stack(PSTACK pS, int pos, int *pVal)//这个函数需要考虑的地方不少
{
if (pS->pTop == pS->pBottom)//先是判断空栈,不多说
return false;
int i = 1;//因为栈的第一个节点有实际含义,所以变量i 的初始值为:1
PNODE p = pS->pTop;
if (pos == 1)//一定要注意,栈的第一个元素是一个节点,不同于链表
//所以第一个节点需要单独拿出来操作,说白了,自己很弱,不知道怎么搞。。只能这样。
{
pS->pTop = p->pNext;
*pVal = p->data;
free(p);
p = NULL;
return true;
}//要点:删除元素需要循环到的位置 是输入节点位置的前一个节点!p->pNext是要删除的节点!
// 删除元素的位置必须是尾节点之前,并且不包括尾节点!因为尾节点以及之后不能删除!
//所以p->pNext!=pS->pBottom!
while (i < pos - 1 && p->pNext != pS->pBottom)
{
i++;
p = p->pNext;
}
if (i > pos - 1 || p->pNext == pS->pBottom)
return false;
PNODE q = p->pNext;//正常步骤
p->pNext = q->pNext;
*pVal = q->data;
free(q);
q = NULL;
return true;
}
栈的特定节点增加
bool Insert_stack(PSTACK pS, int pos, int val)//其考虑点与删除函数差不多,但函数核心各不相同
{
if (pS->pTop == pS->pBottom)//判断空栈,不多说
return false;
if (pos == 1)//如果增加第一个节点,需要单独拿出来进行操作
//与单链表不同的是:栈的首节点为有效节点,所以操作与链表大同小异
{
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
pNew->pNext = pS->pTop;
pS->pTop = pNew;
return true;
}
//要点:增加元素需要循环到的位置 是输入节点位置的前一个节点!p->pNext是要增加的节点!
// 增加元素的位置必须是尾节点之前,并且包括尾节点!所以是 p != pS->pBottom
// 如果 p 是尾节点的话,p->pNext == NULL,pNew->pNext = p->pNext;p->pNext = pNew;
// 这样就相等于在尾节点后面增加了一个节点,而这个节点是永远遍历不到的,是错误的;
// 所以增加节点的位置必须在尾节点以及尾节点之前!
int i = 1;//因为栈的第一个节点有实际含义,所以变量i 的初始值为:1
PNODE p = pS->pTop;
while (i < pos - 1 && p != pS->pBottom)
{
i++;
p = p->pNext;
}
if (i > pos - 1 || p == pS->pBottom)
return false;
PNODE pNew = (PNODE)malloc(sizeof(NODE));//正常步骤
pNew->data = val;
pNew->pNext = p->pNext;
p->pNext = pNew;
return true;
}
代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Node
{
int data;
struct Node * pNext;
}NODE, *PNODE;
typedef struct Stack
{
PNODE pTop;
PNODE pBottom;
}STACK, *PSTACK;
int Length_stack(PSTACK);
void Init_stack(PSTACK);
void Push_stack(PSTACK);
void Traverse_stack(PSTACK);
void Sort_stack(PSTACK);
void Pop_stack(PSTACK, int *);
bool Empty_stack(PSTACK);
bool Delete_stack(PSTACK, int, int *);
bool Insert_stack(PSTACK, int, int);
bool Clear_stack(PSTACK);
int main(void)
{
STACK S;
Init_stack(&S);
Push_stack(&S);
Empty_stack(&S);
if (Empty_stack(&S))
printf("栈为空\n");
else
{
printf("栈不空\n");
printf("遍历栈,得:");
Traverse_stack(&S);
int len = Length_stack(&S);
printf("栈节点的个数为:%d\n", len);
Sort_stack(&S);
printf("经排序后,遍历得:");
Traverse_stack(&S);
int Val;
Pop_stack(&S, &Val);
printf("出栈一次,出栈元素为:%d\n", Val);
printf("出栈后,遍历栈,得:");
Traverse_stack(&S);
int pos1;
int val;
printf("请输入您要删除节点的位置:");
scanf("%d", &pos1);
if (Delete_stack(&S, pos1, &val))
{
printf("出栈的元素是:%d\n", val);
printf("遍历栈,得:");
Traverse_stack(&S);
}
else
printf("您输入的节点位置有误\n");
int pos2;
printf("请输入您要增加节点的位置:");
scanf("%d", &pos2);
int val2;
printf("请输入您要增加节点的值:");
scanf("%d", &val2);
if (Insert_stack(&S, pos2, val2))
{
printf("遍历栈,得:");
Traverse_stack(&S);
}
else
printf("您输入的节点位置有误\n");
if (Clear_stack(&S))
printf("目前栈为空\n");
else
printf("清除失败\n");
}
return 0;
}
void Init_stack(PSTACK pS)
{
pS->pTop = (PNODE)malloc(sizeof(NODE));
pS->pBottom = pS->pTop;
pS->pBottom->pNext = NULL;
return;
}
void Push_stack(PSTACK pS)
{
printf("请输入那您要生成节点的个数:");
int len;
scanf("%d", &len);
for (int i = 1;i <= len;i++)
{
PNODE pNew = (PNODE)malloc(sizeof(NODE));
printf("请输入第%d个节点的值:", i);
scanf("%d", &pNew->data);
pNew->pNext = pS->pTop;
pS->pTop = pNew;
}
return;
}
void Traverse_stack(PSTACK pS)
{
PNODE p = pS->pTop;
while (p != pS->pBottom)
{
printf("%d ", p->data);
p = p->pNext;
}
printf("\n");
return;
}
bool Empty_stack(PSTACK pS)
{
if (pS->pTop == pS->pBottom)
return true;
else
return false;
}
void Pop_stack(PSTACK pS, int *Val)
{
PNODE q = pS->pTop;
pS->pTop = q->pNext;
*Val = q->data;
free(q);
q = NULL;
return;
}
bool Delete_stack(PSTACK pS, int pos, int *pVal)
{
if (Empty_stack(pS))
return false;
int i = 1;
PNODE p = pS->pTop;
if (pos == 1)
{
pS->pTop = p->pNext;
*pVal = p->data;
free(p);
p = NULL;
return true;
}
while (p->pNext != pS->pBottom && i < pos - 1)
{
p = p->pNext;
i++;
}
if (i > pos - 1 || p->pNext == pS->pBottom)
return false;
PNODE q = p->pNext;
*pVal = q->data;
p->pNext = q->pNext;
free(q);
q = NULL;
return true;
}
bool Insert_stack(PSTACK pS, int pos, int val)
{
if (Empty_stack(pS))
return false;
if (pos == 1)
{
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
pNew->pNext = pS->pTop;
pS->pTop = pNew;
return true;
}
int i = 1;
PNODE p = pS->pTop;
while (p != pS->pBottom && i < pos - 1)
{
i++;
p = p->pNext;
}
if (i > pos - 1 || p == pS->pBottom)
return false;
PNODE pNew = (PNODE)malloc(sizeof(NODE));
pNew->data = val;
pNew->pNext = p->pNext;
p->pNext = pNew;
return true;
}
bool Clear_stack(PSTACK pS)
{
if (Empty_stack(pS))
return false;
PNODE p = pS->pTop;
PNODE q = NULL;
while (p != pS->pBottom)
{
q = p->pNext;
free(p);
p = q;
}
pS->pTop = pS->pBottom;
return true;
}
int Length_stack(PSTACK pS)
{
PNODE p = pS->pTop;
int len = 0;
while (p != pS->pBottom)
{
len++;
p = p->pNext;
}
return len;
}
void Sort_stack(PSTACK pS)
{
int i, j, temp;
PNODE p, q;
int len = Length_stack(pS);
for (p = pS->pTop, i = 0;i<len - 1;i++, p = p->pNext)
{
for (q = p->pNext, j = i + 1;j<len;j++, q = q->pNext)
{
if (p->data<q->data)
{
temp = p->data;
p->data = q->data;
q->data = temp;
}
}
}
return;
}
本文深入讲解了栈这一数据结构的概念、特点及其实现方法。详细介绍了栈的基本操作,如初始化、遍历、判断空栈、求栈长度、压栈、出栈等,并探讨了栈的排序、特定节点的删除与插入等高级操作。
3889

被折叠的 条评论
为什么被折叠?



