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

```顺序栈动态内存分配
#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。

静态数组实现顺序栈
#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作为存储空间,队列的长度是确定的,存储空间是线性排列的。

创建空队列

假溢出

顺序队列
#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字段来记录队列的长度。


循环队列
#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。