开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情
数据结构
第三章
第一节 栈和队列的定义及特点 下
采用链栈实现
- 链栈是一个运算受限的单链表,只能在链表头部进行操作
- 链栈类型定义
typedef struct StackNode{
ElemType data;
struct StackNode *next;
}StackNode,*LinkStack;
- 链栈结构表示
- 链栈的头指针就是栈顶,尾指针就是栈底
- 特点:基本不存在栈满的情况,在已知头节点的情况下,删除和插入节点比较方便(因为插入只能在栈顶进行,不能在其他地方插入,所以较为方便)。
链栈的一些基本操作
初始化栈
void create(LinkNode node){//初始化一个空链表
//创建一个头节点
node->next=NULL;//如果想要创建一个空节点,就不能给节点初始化空间,否则他的指针域当前读取的就是一个地址值,而不是NULL了
}
入栈
void push(LinkNode node,ElemType e){//入栈(后进先出)
LinkNode p;
p=(LinkNode)malloc(sizeof(StockNode));//创建新节点
p->data=e;//给数据域赋值
p->next=node->next;//将p节点作为头节点
node->next=p;
printf("值:%d",p->data);
}
弹栈
void pop(LinkNode node){
int e;
LinkNode p;
p=node;
if(p->next==NULL){
printf("是空栈");
return;
}
p=p->next;
e=p->data;
printf("出栈:%d",p->data);
node->next=p->next;//使头节点指向p的下一个节点NULL
free(p);
}
销毁栈
void destroyNode(LinkNode node){
LinkNode p;
if(node->next!=NULL){//栈不为空
p=node->next;//由于初始化带了头节点,因此p要指向头节点的下一个节点
while(p->next!=NULL){//只要节点不为空就执行
node=p->next;
free(p);
p=node;
printf("值为多少:%d\n",p->data);
}
free(p);//释放节点
}
}
队列的表示与实现
队列的数据类型定义
采用顺序队实现
概念:
- 空队:队尾和队头在初始位置(队头位置为-1)
- 实现:队尾==队头
- 队满:队尾在最后一个位置,队头在初始位置;队尾与队头重合(队头位置不为-1) - 实现:1.另外设置一个标志区别空队和队满;2.设置一个变量,记录元素个数对比;3.少用一个元素空间:(rear+1)%MAXSIZE==base(待测试)
顺序队的特点
简单,方便,但易溢出
此处队尾用rear表示,队头用base表示,长度用MAXSIZE表示
- 真溢出:当base==-1,rear==MAXSIZE时,在入队,就出现真溢出,所有空间都被使用了。
- 假溢出:当base!=-1,rear==MAXSIZE时,再入队,就出现假溢出,队尾前还有空余的空间没被使用。
解决假溢出的办法:
- 将队中元素依次往前移.
- 缺点:浪费时间,每移动一次,就需要移动大量元素,很麻烦。
- 使用循环队列:分配给栈的m个空间可以循环使用,当栈尾到了指定长度之后,如果前面的元素是空闲的,就可以从头使用空闲的位置。
-
实现:利用%运算。当栈尾到了指定长度n-1之后,使其加一到长度n,再与长度n模除得到初始位置。例如,当base!=0, rear=n-1,如果rear+1==n,则(rear+1)%n得到初始位置,这时候再进行入队操作就可以了。
-