顺序栈与队列

296 阅读4分钟

区别


数据结构特点
顺序栈(Sequential Stack)一种栈的存储方式,它使用数组实现。顺序栈具有后进先出(LIFO,Last-In, First-Out)的特性,只能从栈顶进行插入和删除操作。在顺序栈中,栈顶指针会随着元素的插入和删除而移动。
链表(Linked List)一种动态数据结构,它由若干个节点组成,每个节点包含存储的数据和指向下一个节点的指针。链表可以分为单链表、双链表和循环链表等形式。链表的插入和删除操作比较灵活,但访问节点需要遍历整个链表。
顺序表(Sequential List)一种线性表的存储方式,它使用数组实现。顺序表中的元素在内存中按照顺序依次存放,可以通过数组的下标进行快速访问。顺序表的插入和删除操作可能涉及数组元素的移动,效率较低。
队列(Queue)一种先进先出(FIFO,First-In, First-Out)的数据结构,类似于现实生活中的排队。队列具有两个指针,一个指向队头,一个指向队尾。元素从队尾插入,从队头删除。队列可以使用数组或链表实现,具体实现方式有顺序队列、链式队列和循环队列等。
链栈(Link)链栈实际上就是一个只能采用头插法插入或删除数据的链表
链队列(Linkqueue)用单链表实现先进先出的队列链式存储结构

顺序栈

顺序栈分为两类

1.动态内存分配:通过指针来表示栈顶和栈底的位置。可以动态调整栈的大小,不受固定容量的限制

1693914595137(1).jpg

```顺序栈动态内存分配
#include <stdio.h>
#include <stdlib.h>
#include <iostream>  //使用cout
#define true 1
#define false 0

#define MAXSIZE 100//顺序栈存储空间的初始分配量

typedef int Elemtype; //自定义顺序栈的数据元素类型
typedef int Status;

typedef struct {
	Elemtype *top;   //栈顶指针
	Elemtype *base; //栈底
	int stacksize;  //该栈的最大容量
}SqStack;

Status Init_SqStack(SqStack &s){
	//创建空栈
	s.base = (Elemtype*)malloc(MAXSIZE*sizeof(Elemtype));
	if(NULL==s.base) return 0;//分配存储空间失败
	s.top = s.base;//top初始值为base,为空栈
	s.stacksize = MAXSIZE;
	return 1;
	
}
Status Push_SqStack(SqStack &s,Elemtype e){
	if(s.top-s.base>=s.stacksize) return 0;
	*(s.top) = e;
	s.top++;
	return 1;
}

Status Pop_SqStack(SqStack &s,Elemtype &e){
	if(s.top==s.base) return 0;//判栈空
	s.top--;
	e = *(s.top);
	return 1;	
}

void Clean_SqStack(SqStack &s){  //清空顺序栈
	if(s.base){
		s.top = s.base;
		std::cout<<"成功清空"<<std::endl;
	}else std::cout<<"栈已经被销毁,无需清空"<<std::endl;
}

//销毁顺序栈,delete将整个s.base从内存中删除
void Destroy_SqStack(SqStack &s){
	if(s.base){
		delete s.base;
		s.stacksize = 0;
		s.top = NULL;
		s.base = NULL;
		std::cout<<"销毁成功!"<<std::endl;
	}else std::cout<<"栈已经被销毁,无需销毁"<<std::endl;
}
Status GetTop_SqStack(SqStack &s,Elemtype &e){
	if(s.top==s.base) return 0;//判栈空
	e = *(s.top-1);
	return e;
}

int Length_SqStack(SqStack s){
	if(s.top==s.base) return 0;
	s.stacksize = s.top - s.base;//栈内元素个数
	return s.stacksize;
}

Status Print_SqStack(SqStack s){
	int len = Length_SqStack(s);
	for(int i=1;i<=len;i++){
		printf("%d: %2d\n",i,*(s.top-i));
	}
	return 1;
}

//十进制转八进制
void conversion(){
	SqStack s;
	int n;
	int e;
	Init_SqStack(s);
	printf("十进制转八进制,输入十进制数");
	scanf("%5d",&n);
	while(n){
		Push_SqStack(s,n%8);
		n=n/8;
	};
	printf("输出八进制\n");
	while(s.top!=s.base){
		Pop_SqStack(s,e);
		printf("%5d\n",e);	
	}	
}

int main(){
	SqStack s;
	Init_SqStack(s);
	printf("输入顺序栈");
	int x;
	scanf("%d",&x);
	while(x!=0){
		Push_SqStack(s,x);
		scanf("\n%d",&x);
	}
	printf("输出顺序栈");
	Print_SqStack(s);
	printf("栈顶元素:%2d\n",GetTop_SqStack(s,x));
	printf("栈中元素的个数是:%d\n",Length_SqStack(s));	
	printf("出栈2次");
	Pop_SqStack(s,x);
	Pop_SqStack(s,x);
    printf("打印出栈结果\n");
	Print_SqStack(s);
   conversion();
   
//   清空顺序栈
Clean_SqStack(s);
	//销毁顺序栈
	Destroy_SqStack(s);	
}

```js
2.静态数组作为存储空间:通过top来表示栈顶的位置。它的容量是固定的,预先定义了最大容量MaxSize。

1693915314938.jpg

静态数组实现顺序栈
#include <stdio.h>
#include <stdlib.h>
#define true 1
#define false 0
#define MaxSize 50 //定义栈中元素最大的个数
 
// 顺序栈的数据结构
typedef int Elemtype; //自定义顺序栈的数据元素类型

typedef struct SqStack
{
	Elemtype data[MaxSize];
	int top;
}SqStack;

//初始化顺序栈
char Initstack(SqStack *s)  //指针可以改变元素
{
	s->top = -1;//也是判空条件
}

//判空
char StackEmpty(SqStack s)
{
	if(s.top==-1) return true;
	else return false;
}
//进栈
char Push(SqStack *s,Elemtype e)
{
	if(s->top == MaxSize - 1) return false;//判栈满
	s->data[++s->top] = e;
	return true;
}

//出栈
char Pop(SqStack *s,Elemtype *e)  //*e指针形式能够把出栈元素带出
{
	if(StackEmpty(*s)) return false;
	*e = s->data[s->top--];
	return true;
}

//读栈顶元素
char GetTop(SqStack s,Elemtype *e)
{
	if(StackEmpty(s)) return false;
	*e = s.data[s.top];
	return *e;
}

int main()
{
	SqStack s;
	Initstack(&s);
	Push(&s,1);
	Push(&s,2);
	Push(&s,3);
	Elemtype X; //保存出栈元素和栈顶元素
	int count = s.top;
	for(int i=0;i<=count;i++){
		printf("i=%d\n",i);
		GetTop(s,&X);
		printf("GetTop X = %d\n",X);
	}	
}
如果需要动态调整栈的大小,并且不确定栈的最大容量,可以选择第一种顺序栈。如果栈的大小固定,并且不需要频繁地调整大小,可以选择第二种顺序栈,它在空间利用上更加高效。

队列

队列分为两类

1.顺序队列(SqQueue): 使用数组data作为存储空间,队列的长度是确定的,存储空间是线性排列的。

1693916023321.jpg

创建空队列

1693916079865.jpg

假溢出

1693916337955.jpg

顺序队列
#include <stdio.h>
#include <stdlib.h>
#include <iostream>  //使用cout

#define true 1
#define false 0
#define MAXSIZE 100

typedef int status;
typedef int Elemtype;

typedef struct {
	Elemtype data[MAXSIZE];
	int front;
	int rear;
}SqQueue;

//初始化队列
status InitQueue_Sq(SqQueue &Q){
	Q.front = Q.rear = 0;
	return true;	
}
 
//判空
status QueueEmpty_Sq(SqQueue Q){
	return Q.front == Q.rear;
}

//判满
status QueueFull_Sq(SqQueue Q){
	return Q.front == (Q.rear+1) % MAXSIZE;
}

//队尾入队
status EnQueue_Sq(SqQueue &Q,Elemtype e){
	if(QueueFull_Sq(Q)){
		std::cout<<"Queue is full.\n"<<std::endl;
		return false;
	}
	Q.data[Q.rear] = e;
	Q.rear = (Q.rear + 1) % MAXSIZE;
	return true;
}

//队尾出队
status DeQueue_Sq(SqQueue &Q,Elemtype &e){
	if(QueueEmpty_Sq(Q)){
		std::cout<<"Queue is empty.\n";
		return false;
	}
	e = Q.data[Q.front];
	Q.front = (Q.front +1) %MAXSIZE;
	return true;
}

//获取队头元素
Elemtype GetTop_Sq(SqQueue Q,Elemtype &e){
	if(QueueEmpty_Sq(Q)){
			std::cout<<"Queue is empty.\n";
			return false;
	}
	
	e = Q.data[Q.front];
	return e;
}

//销毁队列
status DestroyQueue_Sq(SqQueue &Q){
	Q.front = Q.rear =0;
	std::cout<<"销毁成功!\n";
	return true;
}

//置空队列
status ClearQueue_Sq(SqQueue &Q){
	if(QueueEmpty_Sq(Q)){
		std::cout<<"已置空队列!\n";
	}
	while(!QueueEmpty_Sq(Q)){
		Elemtype e;
		DeQueue_Sq(Q,e);
	}
	return true;
}

// 获取队列长度
int QueueLength_Sq(SqQueue Q) {
    return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

int main(){
	SqQueue Q;
	Elemtype e;
	InitQueue_Sq(Q);
	EnQueue_Sq(Q,1);
	EnQueue_Sq(Q,2);
	EnQueue_Sq(Q,3);
	EnQueue_Sq(Q,4);
	while(!QueueEmpty_Sq(Q)){
		printf("%d\n",GetTop_Sq(Q,e));
		DeQueue_Sq(Q,e);
	}
	printf("队列长度:%d\n",QueueLength_Sq(Q));
	DestroyQueue_Sq(Q);
	ClearQueue_Sq(Q);
}
2.循环队列(ClenQueue):使用数组elem作为存储空间。通过将队列的头尾连接起来形成一个环,实现了循环使用存储空间的效果。它可以更有效地利用存储空间,但需要额外的length字段来记录队列的长度。

1693916234704.jpg

1693916202359.jpg

循环队列
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define true 1
#define false 0

#define MAXSIZE 100
typedef int Elemtype;
typedef int status;
typedef struct {
	Elemtype elem[MAXSIZE];   //存储空间
	int length;
	int rear;
}ClenQueue;//循环队列

status InitQueue_Sq(ClenQueue &Q){
	Q.length = 0;
	Q.rear = 0;
	return true;	
}
 
//判空
status QueueEmpty_Sq(ClenQueue Q){
	if(Q.length==0){
		return true;
	}else return false;
}

//判满
status QueueFull_Sq(ClenQueue Q){
	if(Q.length==MAXSIZE) return true;
	else return false;
}

//队尾入队
status EnQueue_Sq(ClenQueue &Q,Elemtype e){
	if(QueueFull_Sq(Q)){
		std::cout<<"Queue is full.\n"<<std::endl;
		return false;
	}
	Q.elem[Q.rear] = e;
	Q.rear = (Q.rear + 1) % MAXSIZE;
	Q.length++;
	return true;
}

//队头出队
status DeQueue_Sq(ClenQueue &Q,Elemtype &e){
	if(QueueEmpty_Sq(Q)){
		std::cout<<"Queue is empty.\n";
		return false;
	}
	e = Q.elem[0];
	for(int i=0;i<Q.length-1;i++){
		Q.elem[i]=Q.elem[i+1];
	}
	Q.rear = (Q.rear-1 +MAXSIZE) %MAXSIZE;
	Q.length--;
	return true;
}


Elemtype GetTop_Sq(ClenQueue Q,Elemtype &e){
	if(QueueEmpty_Sq(Q)){
			std::cout<<"Queue is empty.\n";
			return false;
	}
	e = Q.elem[0];
	return e;
}

status DestroyQueue_Sq(ClenQueue &Q){
	Q.length=0;
	 Q.rear =0;
	 free(Q.elem);//释放内存
	std::cout<<"销毁成功!\n";
	return true;
}

status ClearQueue_Sq(ClenQueue &Q){
	if(QueueEmpty_Sq(Q)){
		std::cout<<"已置空队列!\n";
	}
	Q.length=0;
	Q.rear =0;
	return true;
}

int main(){
	ClenQueue Q;
	InitQueue_Sq(Q);	
}
如果队列的长度是确定的,并且存储空间有限,可以选择SqQueue。如果需要循环使用存储空间,可以选择ClenQueue。