开始学习数据结构时,还是很有必要自己手动撸一遍来实现各个功能的。
目录
这次记的是栈和队列两种结构,栈和队列本质上也属于一种线性表,不过在表头或是表尾赋予了其特殊含义,即栈的表头元素称为栈底,表尾元素称为栈顶,相关操作总是在栈顶进行,所以称为后进先出(Last In First Out, LIFO)的线性表;而队列表头元素称为队头,表尾元素称为队尾,相关操作与栈相反,总是在队头进行,所以称为先进先出(First In First Out, FIFO)的线性表。
下面讲几个重要的点:
栈
首先定义一个结构体栈,应包含一个保存元素数据的数组data[ ],其次设置一个栈顶指针top(此处不是真正意义上存地址的指针,只是数组下标的一个标记)实时指向栈顶的下一个元素(与上图显示不同)。
typedef struct
{
SElemType data[MAXSIZE];
int top; //用于栈顶指针
}SqStack;
入栈
入栈操作核心思路就是先将元素赋值给top所指的元素(即原栈顶的下一个元素),然后将top后移一位。
Status Push(SqStack *S, SElemType e)
{
if(S->top == MAXSIZE){ //栈满
printf("栈已满,无法入栈");
return ERROR;
}
S->data[S->top] = e;
S->top++;
return OK;
}
出栈
出栈操作核心思路就是先将top向前移一位,然后top所指的元素值保存在一个元素e里。
Status Pop(SqStack *S, SElemType *e)
{
if(S->top == 0){
printf("栈已空,无法删除栈元素!");
return ERROR;
}
S->top--; //栈顶指针-1
*e = S->data[S->top]; //将要删除的栈顶元素赋值给e
return OK;
}
其他栈的操作:
初始化栈
Status InitStack(SqStack *S)
{
S->top = 0;
return OK;
}
栈是否空
Status StackEmpty(SqStack *S)
{ //空返回1
if (S->top == 0)
return TRUE;
else
return FALSE;
}
栈是否满
Status StackFull(SqStack *S)
{ //满返回1
if (S->top == MAXSIZE)
return TRUE;
else
return FALSE;
}
取栈顶
Status GetTop(SqStack *S, SElemType *e){
if(S->top == 0){
printf("栈已空,无法取栈顶!");
return ERROR;
}
*e = S->data[S->top-1]; //栈顶元素赋值给e
return OK;
}
打印栈的状态
void DisplaySqStack(SqStack *S){
int i;
for(i=S->top-1;i>=0;i--){
printf("%-3d", S->data[i]);
putchar('\n');
}
}
栈长
int SqStackLength(SqStack *S){
return S->top;
}
栈的测试
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100
typedef int Status;
typedef int SElemType;
//栈的顺序结构表示
typedef struct
{
SElemType data[MAXSIZE];
int top; //用于栈顶指针
}SqStack;
//初始化栈
Status InitStack(SqStack *S)
{
S->top = 0;
return OK;
}
//判断栈是否为满
Status StackFull(SqStack *S)
{ //满返回1
if (S->top == MAXSIZE)
return TRUE;
else
return FALSE;
}
//判断栈是否为空
Status StackEmpty(SqStack *S)
{ //空返回1
if (S->top == 0)
return TRUE;
else
return FALSE;
}
//入栈
Status Push(SqStack *S, SElemType e)
{
if(S->top == MAXSIZE){ //栈满
printf("栈已满,无法入栈");
return ERROR;
}
S->data[S->top] = e;
S->top++;
return OK;
}
//出栈
Status Pop(SqStack *S, SElemType *e)
{
if(S->top == 0){
printf("栈已空,无法删除栈元素!");
return ERROR;
}
S->top--;
*e = S->data[S->top]; //将要删除的栈顶元素赋值给e
return OK;
}
//取栈顶元素
Status GetTop(SqStack *S, SElemType *e){
if(S->top == 0){
printf("栈已空,无法取栈顶!");
return ERROR;
}
*e = S->data[S->top-1]; //栈顶元素赋值给e
return OK;
}
//打印出栈现有元素
void DisplaySqStack(SqStack *S){
int i;
for(i=S->top-1;i>=0;i--){
printf("%-3d", S->data[i]);
putchar('\n');
}
}
//返回栈的长度
int SqStackLength(SqStack *S){
return S->top;
}
int main(){
SqStack S;
InitStack(&S);
int i, n;
SElemType e;
printf("需要入栈几个元素?\n");
scanf("%d", &n);
printf("具体元素值\n");
for(i=0;i<n;i++){
scanf("%d", &e);
Push(&S,e);
}
printf("栈的状态\n");
DisplaySqStack(&S);
printf("出栈操作后\n");
Pop(&S,&e);
DisplaySqStack(&S);
printf("取栈顶元素为:");
GetTop(&S,&e);
printf("%d\n", e);
printf("栈的状态\n");
DisplaySqStack(&S);
return 0;
}
队列
考虑到实用性,这里介绍的是循环队列。
首先定义一个结构体队列,应包含一个保存元素数据的数组data[ ],其次设置一个队头(front)和队尾(rear)指针(此处不是真正意义上存地址的指针,只是数组下标的一个标记)分别标记着队列中第一个和最后一个元素的后一位的元素。
初始设置队列为空时,只需让front和rear同时指向第一个元素,同时为了防止假溢出状态,循环队列允许front比rear大(队头比队尾的下标还大),但整个数组空间不会完全利用,要空出一个位置,即
因此判断队列满条件为
,判断队列空条件为
。
入队
入队的核心思路就是先将元素e赋值给rear所指元素,再让rear逻辑上后移一位,即rear=(rear+1)%MAXSIZE。
Status EnQueue(SqQueue *Q, QElemType e){
if((Q->rear+1)%MAXSIZE == Q->front){
printf("队列满,无法入队!");
return ERROR;
}
Q->data[Q->rear]=e;
Q->rear=(Q->rear+1)%MAXSIZE;
return OK;
}
出队
出队的核心思路就是先将front所指元素数据保存在e里,然后再让front逻辑上后移一位,即front=(front+1)%MAXSIZE。
Status DeQueue(SqQueue *Q, QElemType *e){
if(Q->front == Q->rear){
printf("队列空,无法出队!");
return ERROR;
}
*e = Q->data[Q->front];
Q->front=(Q->front+1)%MAXSIZE;
return OK;
}
其他队列的操作:
初始化队列
Status InitQueue(SqQueue *Q){
Q->front=Q->rear=0;
return OK;
}
判断队列空否
Status QueueEmpty(SqQueue *Q){
if(Q->front == Q->rear)
return TRUE;
else return FALSE;
}
判断队列满否
Status QueueFull(SqQueue *Q){
if((Q->rear+1)%MAXSIZE == Q->front)
return TRUE;
else return FALSE;
}
队列长度
int QueueLength(SqQueue *Q){
return (Q->rear-Q->front+MAXSIZE)%MAXSIZE;
}
取队头
Status GetHead(SqQueue *Q, QElemType *e){
if(Q->front == Q->rear){
printf("队列空,无法取队头元素!");
return ERROR;
}
*e = Q->data[Q->front];
return OK;
}
打印队的状态
void DisplayQueue(SqQueue *Q){
int i;
if(Q->rear > Q->front){
for(i=Q->front;i<Q->rear;i++){ //正常状态下
printf("%-3d", Q->data[i]);
}
}
else{
for(i=Q->front;i<Q->rear+MAXSIZE;i++){ //假溢出状态下
if(i>=MAXSIZE){
printf("%-3d", Q->data[i-MAXSIZE]);
}
else{
printf("%-3d", Q->data[i]);
}
}
}
}
队列的测试
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 10000
typedef int Status;
typedef int QElemType;
typedef struct{
QElemType data[MAXSIZE];
int front, rear;
}SqQueue;
//初始化队列
Status InitQueue(SqQueue *Q){
Q->front=Q->rear=0;
return OK;
}
//判断队列空否
Status QueueEmpty(SqQueue *Q){
if(Q->front == Q->rear)
return TRUE;
else return FALSE;
}
//判断队列满否
Status QueueFull(SqQueue *Q){
if((Q->rear+1)%MAXSIZE == Q->front)
return TRUE;
else return FALSE;
}
//队列长度
int QueueLength(SqQueue *Q){
return (Q->rear-Q->front+MAXSIZE)%MAXSIZE;
}
//入队
Status EnQueue(SqQueue *Q, QElemType e){
if((Q->rear+1)%MAXSIZE == Q->front){
printf("队列满,无法入队!");
return ERROR;
}
Q->data[Q->rear]=e;
Q->rear=(Q->rear+1)%MAXSIZE;
return OK;
}
//出队
Status DeQueue(SqQueue *Q, QElemType *e){
if(Q->front == Q->rear){
printf("队列空,无法出队!");
return ERROR;
}
*e = Q->data[Q->front];
Q->front=(Q->front+1)%MAXSIZE;
return OK;
}
//取队头
Status GetHead(SqQueue *Q, QElemType *e){
if(Q->front == Q->rear){
printf("队列空,无法取队头元素!");
return ERROR;
}
*e = Q->data[Q->front];
return OK;
}
//打印队列
void DisplayQueue(SqQueue *Q){
int i;
if(Q->rear > Q->front){
for(i=Q->front;i<Q->rear;i++){ //正常状态下
printf("%-3d", Q->data[i]);
}
}
else{
for(i=Q->front;i<Q->rear+MAXSIZE;i++){ //假溢出状态下
if(i>=MAXSIZE){
printf("%-3d", Q->data[i-MAXSIZE]);
}
else{
printf("%-3d", Q->data[i]);
}
}
}
}
void main(){
SqQueue Q;
InitQueue(&Q);
int i;
QElemType e, n;
printf("需要入队几个元素?\n");
scanf("%d", &n);
printf("具体元素值\n");
for(i=0;i<n;i++){
scanf("%d", &e);
EnQueue(&Q,e);
}
printf("队列的状态\n");
DisplayQueue(&Q);
printf("\n出队操作后\n");
DeQueue(&Q,&e);
DisplayQueue(&Q);
printf("\n取队头元素为:");
GetHead(&Q,&e);
printf("%d\n", e);
printf("队列的状态\n");
DisplayQueue(&Q);
printf("\n再入队:");
scanf("%d", &e);
EnQueue(&Q,e);
printf("队列的状态\n");
DisplayQueue(&Q);
}