数据结构:栈和队列

    栈是在表尾进行插入和删除操作的线性表,允许数据操作的一头称为栈顶,另一端称为栈底,不含数据元素称为空栈。栈即后进先出(LIFO)的线性表。栈和线性表一样,同样有两种存储结构,顺序存储结构和链式存储结构。如果所需的栈大小在可控范围内使用顺序栈,否则使用链栈。

    队列是只允许在一端进行插入,另外一端进行删除操作的线性表。队列即先进先出(FIFO)的线性表。队列和线性表一样,同样有两种存储结构,顺序存储结构和链式存储结构(链队列)。确定队列的最大长度情况下可使用循环队列,否则使用链队列。
    头尾相接的顺序存储结构队列称为循环队列,这也是这篇文章所介绍的,如果不做循环队列,那么每次队列出队后都要把后面的队伍全部向前移动,无疑提高了时间复杂度。循环队列的思想就是,数据入队就在队尾+1,数据出队也让队头+1,可以理解为一个动态的队头,当超过队列长度后,队尾跑回队头的“前面”,但它依然是队尾。结合后面的例子来理解会好点。


实例一:顺序栈

#include "stdio.h"
#define SIZE 5  // 栈的大小

typedef struct
{
	int top;
	int data[SIZE];
}stack;

/*
*	功能:数据人栈
*	输入:堆栈指针,数据
*	输出:无
*/
void push(stack *ps,int data)
{
	ps->data[++ps->top] = data;  // 数组下标先加1,然后把值传入数组
	if(ps->top == SIZE-1)  // 当数组下标到达栈顶时,提示栈满
	{
		printf("full stack\n");
	}
}

/*
*	功能:数据出栈
*	输出:堆栈指针,数据
*	输出:无
*/
void pop(stack *ps,int *data)
{
	if(ps->top>=0)
		*data = ps->data[ps->top--]; // 先将数据出栈,再将栈的游标向下移
	else
		printf("no data\n");
}

void main()
{
	stack sta = {-1};  // 堆栈游标一开始为-1是为了方便出栈入栈的一致操作
	stack *ps = &sta;  // 堆栈指针指向结构体
	int data;
	pop(ps,&data);  // 一开始没有元素可出栈
	push(ps,100);  // 100入栈
	push(ps,101);  // ..
	push(ps,102);  // ..
	push(ps,103);  // ..
	push(ps,104);  // 104入栈,此时栈满
	pop(ps,&data);  // 此时应该是104出栈,赋给data
	printf("%d\n",data);  // 打印data
	printf("%d\n",ps->data[ps->top]);  // 此时栈顶数据为103 
}

打印结果:



实例二:链栈

#include "malloc.h"
#include "stdio.h"

// 堆栈结点
typedef struct stackNode
{
	int data;
	struct stackNode *next;
}stackNode;

/*
*	功能:数据入栈
*	输入:堆栈指针(头指针),数据
*	输出:无
*/
void push(stackNode *h,int data)
{
	stackNode *s = (stackNode *)malloc(sizeof(stackNode));  // 分配结点内存 
	s->data = data;  // 将数据赋给当前结点
	s->next = h->next;  // 头结点的指针域赋给当前结点的指针域
	h->next = s;  // 当前结点指针赋给头结点的指针域
}                              

/*
*	功能:数据出栈
*	输入:堆栈指针(头指针),数据的指针
*	输出:无
*/
void pop(stackNode *h,int *data)
{
	if(h->next != NULL)  // 如果头结点指针域存放数据,即栈是有数据的
	{
		stackNode *s = h->next;  // 出栈的结点
		*data = s->data;  // 数据取出
		h->next = s->next;  // 把头结点的指针指向出栈结点的指针域,即下一个结点
		free(s);  // 释放出栈的结点
	}else
	{
		printf("no element\n");	
	}
}

void main(int argc, char* argv[])
{
	stackNode *h = (stackNode *)malloc(sizeof(stackNode));
	h->next = NULL;  
	push(h,100);  // 100入栈
	push(h,101);  // ..
	push(h,102);  // ..
	push(h,103);  // ..
	push(h,104);  // 104入栈
	int a;
	pop(h,&a);  // 104出栈,赋给变量a,并打印
	printf("%d\n",a);
	pop(h,&a);
	printf("%d\n",a);
	pop(h,&a);
	printf("%d\n",a);
	pop(h,&a);
	printf("%d\n",a);
	pop(h,&a);
	printf("%d\n",a);
	pop(h,&a);  // 没有元素出栈,会提示错误
}

打印结果:



实例三:循环队列

// 循环队列.cpp : Defines the entry point for the console application.

#include "stdafx.h"
#include "stdio.h"
#include "malloc.h"
#define SIZE 5

// 循环队列的结构体
typedef struct
{
	int data[SIZE];
	int front;
	int rear;
}queue;

/*
*	功能:数据入队
*	输入:队列结构体指针,数据
*	输出:无
*/
void enQueue(queue *q,int data)
{
	if((q->rear+1)%SIZE == q->front)   // 由于FIFO,队头位置永远不会比队尾大,
		printf("can not insert, the quequ is full\n"); // 所以当队尾循环一圈还差一个数据赶上队头时,表明队列已满,如果不留一// 个数据位置,那么队满和空队列都是front == rear这个条件,两者会有点难以区分。
	else                               
	{
		q->data[q->rear] = data;
		q->rear = (q->rear+1)%SIZE;    // 循环队列最重要的一句其实就是这句(rear+1)%SIZE
	}
}

/*
*	功能:数据入队
*	输入:队列结构体指针,数据指针
*	输出:无
*/
void deQueue(queue *q,int *data)
{
	if(q->front == q->rear)
		printf("the queue is empty\n");
	else
	{
		*data = q->data[q->front];
		q->front = (q->front+1)%SIZE;
	}
}

void main(int argc, char* argv[])
{
	int data;
	queue *que = (queue *)malloc(sizeof(queue));  // 队列初始化
 	que->front = 0;
	que->rear = 0; 
	
	deQueue(que,&data);  // 一开始没有数据出队,打印错误

	enQueue(que,100);  // 101-103入队,
	enQueue(que,101);
	enQueue(que,102);
	enQueue(que,103);  // 队列长度为5,其实是4个,此时队列满

	enQueue(que,104);  // 数据再入队会打印错误
	
	for(int i = 0; i < 4; i++)  // 101-103出队,打印出来,此时队列空 
	{
		deQueue(que,&data);
		printf("%d\n",data);
	}
	deQueue(que,&data);  // 再出队,打印错误
}

// 当队尾在队头后面时,此时队列长度为: rear - front
// 当队尾循环到前面来了后,队列长度为 rear + (size - front)
// 所以得出的队列长度算法是: (rear-front+size)%size

打印结果:



实例四:链队列

// 链队列.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdio.h"
#include "malloc.h"

/*
*	队列结点
*/
typedef struct qNode
{
	int data;
	struct qNode *next;
}qNode;

/*
*	队头队尾结构体
*/
typedef struct 
{
	qNode *front,*rear;
}queue;

/*
*	功能:数据入队
*	输入:队头队尾结构体指针,入队数据
*	输出:无
*/
void enQueue(queue *q, int data)
{
	qNode *s = (qNode *)malloc(sizeof(qNode));  // 插入的队列结点
	s->data = data;  // 结点数据
	s->next = NULL;  // 结点的指针域为NULL
	q->rear->next = s;  // 当前队尾的指针域为当前结点地址
	q->rear = s;  // 现在队尾是当前结点	
}

void deQueue(queue *q, int *data)
{
	if(q->front == q->rear)  // 当队头尾一样的时候,说明没有队列没有元素
	{
		printf("no data in the queue\n");
	}
	else 
	{
		qNode *s;  // 结点指针
		s = q->front->next;  // 出队时,总是出头结点的指针域,即第一个结点
		*data = s->data;  
		q->front->next = s->next;  // 把头结点的指针域设为当前结点的指针域
		if(q->rear == s)  // 当队尾为第一个结点时(注意第一个结点不是头结点),将队尾指向头结点
		{
			q->rear = q->front;
		}
		free(s);  // 将第一个结点释放 
	}
}	

void main(int argc, char* argv[])
{
	int data;
	queue *q = (queue *)malloc(sizeof(queue));  // 队头队尾结构体指针
	qNode *h = (qNode *)malloc(sizeof(qNode));  // 头结点结构体指针
	q->front = h;  // 队头和队尾都指向头结点
	q->rear = h;

	deQueue(q,&data);  // 没有元素出队,打印错误

	enQueue(q,100);  // 100、101、102入队
	enQueue(q,101);
	enQueue(q,102);
	
	deQueue(q,&data);  // 100、101、102出队,打印出来
	printf("%d\n",data);
	deQueue(q,&data);
	printf("%d\n",data);
	deQueue(q,&data);  // 执行此次出队时,队尾为第一个结点,队头队尾都指向头结点了,可返回去看函数
	printf("%d\n",data);
	
	deQueue(q,&data);  // 再出队没有元素,打印错误

	enQueue(q,103);  // 103入队出队,打印出来
	deQueue(q,&data);
	printf("%d\n",data);
}
打印结果:


    

    小结:栈是一种后进先出的线性表数据结构,可分为顺序栈和链栈;队列是一种先进先出的线性表数据结构,可分为顺序队列,其中又以循环队列为重,和链队列。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值