数据结构 第三章栈和队列 第一节 下

132 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情

数据结构

第三章

第一节 栈和队列的定义及特点 下

采用链栈实现

  • 链栈是一个运算受限的单链表,只能在链表头部进行操作
  • 链栈类型定义
typedef struct StackNode{
    ElemType data;
    struct StackNode *next;
}StackNode,*LinkStack;
  • 链栈结构表示
    • 链栈的头指针就是栈顶,尾指针就是栈底
    • 特点:基本不存在栈满的情况,在已知头节点的情况下,删除和插入节点比较方便(因为插入只能在栈顶进行,不能在其他地方插入,所以较为方便)。 image.png

链栈的一些基本操作

初始化栈

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);//释放节点
	}
}

队列的表示与实现

队列的数据类型定义

image.png image.png

采用顺序队实现
概念:
  • 空队:队尾和队头在初始位置(队头位置为-1)
    • 实现:队尾==队头
  • 队满:队尾在最后一个位置,队头在初始位置;队尾与队头重合(队头位置不为-1) - 实现:1.另外设置一个标志区别空队和队满;2.设置一个变量,记录元素个数对比;3.少用一个元素空间:(rear+1)%MAXSIZE==base(待测试)
顺序队的特点

简单,方便,但易溢出

此处队尾用rear表示,队头用base表示,长度用MAXSIZE表示

  • 真溢出:当base==-1,rear==MAXSIZE时,在入队,就出现真溢出,所有空间都被使用了。 image.png
  • 假溢出:当base!=-1,rear==MAXSIZE时,再入队,就出现假溢出,队尾前还有空余的空间没被使用。 image.png 解决假溢出的办法:
  1. 将队中元素依次往前移.
    • 缺点:浪费时间,每移动一次,就需要移动大量元素,很麻烦。
  2. 使用循环队列:分配给栈的m个空间可以循环使用,当栈尾到了指定长度之后,如果前面的元素是空闲的,就可以从头使用空闲的位置。
    • 实现:利用%运算。当栈尾到了指定长度n-1之后,使其加一到长度n,再与长度n模除得到初始位置。例如,当base!=0, rear=n-1,如果rear+1==n,则(rear+1)%n得到初始位置,这时候再进行入队操作就可以了。