数据结构与算法:栈和队列

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。 栈中的数据元素遵守后进先出 LIFO Last In First Out )的原则。
压栈:栈的插入操作叫做进栈 / 压栈 / 入栈, 入数据在栈顶
出栈:栈的删除操作叫做出栈。 出数据也在栈顶

栈的实现一般可以使用顺序表 或者链表实现 ,相对而言顺序表的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

 

顺序表实现栈

Stack.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>


typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;		// 标识栈顶位置的
	int capacity;
}ST;

void STInit(ST* pst);
void STDestroy(ST* pst);

// 栈顶插入删除
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);

bool STEmpty(ST* pst);
int STSize(ST* pst);

Stack.c

#include"Stack.h"

void STInit(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	pst->capacity = 0;

	// 表示top指向栈顶元素
	pst->top = -1;
}

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);
	pst->a = NULL;
	pst->top = -1;
	pst->capacity = 0;
}

// 栈顶插入删除
void STPush(ST* pst, STDataType x)
{
	assert(pst);

	if (pst->top + 1 == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		pst->a = tmp;
		pst->capacity = newcapacity;
	}
    pst->top++;
	pst->a[pst->top] = x;
	
}

void STPop(ST* pst)
{
	assert(pst);
	// 不为空
	assert(pst->top > -1);

	pst->top--;
}

STDataType STTop(ST* pst)
{
	assert(pst);
	// 不为空
	assert(pst->top > -1);

	return pst->a[pst->top];
}

bool STEmpty(ST* pst)
{
	assert(pst);

	return pst->top == -1;
}

int STSize(ST* pst)
{
	assert(pst);

	return pst->top+1;
}

text.c

#include"Stack.h"
void menu() {
	printf("********************栈**********************\n");
	printf("******1、入栈          2、出栈**************\n");
	printf("******3、打印栈顶元素***********************\n");
	printf("******4、打印全部栈元素*********************\n");
	printf("******5、判断栈是否为空*********************\n");
	printf("******6、打印栈的元素个数*******************\n");
}
int main()
{
	ST s;
	STInit(&s);
	int op;
	STDataType x;

	do {
     menu();
	 printf("请选择您的操作:\n");
	 scanf("%d", &op);
	 switch (op)
	 {
	 case 1:
		 printf("请输入栈的数据:\n");
		 scanf("%d", &x);
		 STPush(&s,x);
		 break;
	 case 2:
		 STPop(&s);
		 break;
	 case 3:
		 printf("%d\n", STTop(&s));
		 break;
	 case 4:
		 while (!STEmpty(&s))
			 	{
			 		printf("%d ", STTop(&s));
			 		STPop(&s);
			 	}
		 printf("\n");
		 break;
	 case 5:
		 if (STEmpty(&s))
			 printf("栈为空\n");
		 else
		 {
			 printf("栈不为空\n");
		 }
		 break;
	 case 6:
		 printf("%d\n",STSize(&s));
		 break;
	 case 0:
		 printf("goodby");
		 break;
	 default:
		 printf("您的输入有误,请重新输入\n");
		 break;
	 }
	}while(op);
	STDestroy(&s);
	return 0;
}

相关例题

1.一个栈的初始状态为空。现将元素12345ABCDE依次入栈,然后再依次出栈,则元素出
栈的顺序是( )。
A 12345ABCDE
B EDCBA54321
C ABCDE12345
D 54321EDCBA

解:B (显而易见)

2.若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
A 1,4,3,2
B 2,3,4,1
C 3,1,4,2
D 3,4,2,1

解:A: 1先进栈再出栈,接着2,3,4依次进栈,再依次出栈,4,3,2

       B: 1,2先进栈,2再出栈,3进栈再出栈,4进栈,最后4,1全部出栈

       C: 不可能,3第一个出栈,后面出栈的要么是4或者是2

       D: 1,2,3依次进栈,接着3出栈,然后4进栈再出栈,最后2,1依次出栈

答案选 C

3.

typedef int STDataType;

typedef struct Stack
{
    STDataType* a;
    int top;        // 标识栈顶位置的
    int capacity;
}ST;

void STInit(ST* pst)
{
    assert(pst);

    pst->a = NULL;
    pst->capacity = 0;

    // 表示top指向栈顶元素
    pst->top = -1;
}

void STDestroy(ST* pst)
{
    assert(pst);

    free(pst->a);
    pst->a = NULL;
    pst->top = -1;
    pst->capacity = 0;
}

// 栈顶插入删除
void STPush(ST* pst, STDataType x)
{
    assert(pst);

    if (pst->top + 1 == pst->capacity)
    {
        int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
  STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
        if (tmp == NULL)
        {
            perror("realloc fail");
            return;
        }

        pst->a = tmp;
        pst->capacity = newcapacity;
    }
    pst->top++;
    pst->a[pst->top] = x;    
}

void STPop(ST* pst)
{
    assert(pst);
    // 不为空
    assert(pst->top > -1);

    pst->top--;
}

STDataType STTop(ST* pst)
{
    assert(pst);
    // 不为空
    assert(pst->top > -1);

    return pst->a[pst->top];
}

bool STEmpty(ST* pst)
{
    assert(pst);

    return pst->top == -1;
}

这里将我们的栈的操作代码粘贴上去就行了,利用栈进行判断会方便得多

4.

说明:

  • 只能使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;		// 标识栈顶位置的
	int capacity;
}ST;

void STInit(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	pst->capacity = 0;

	// 表示top指向栈顶元素
	pst->top = -1;
}

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);
	pst->a = NULL;
	pst->top = -1;
	pst->capacity = 0;
}

// 栈顶插入删除
void STPush(ST* pst, STDataType x)
{
	assert(pst);

	if (pst->top + 1 == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		pst->a = tmp;
		pst->capacity = newcapacity;
	}
    pst->top++;
	pst->a[pst->top] = x;
	
}

void STPop(ST* pst)
{
	assert(pst);
	// 不为空
	assert(pst->top > -1);

	pst->top--;
}

STDataType STTop(ST* pst)
{
	assert(pst);
	// 不为空
	assert(pst->top > -1);

	return pst->a[pst->top];
}

bool STEmpty(ST* pst)
{
	assert(pst);

	return pst->top == -1;
}


typedef struct {
    ST pushst;
    ST popst;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));

    STInit(&obj->pushst);
    STInit(&obj->popst);
    
    return obj;
}

void myQueuePush(MyQueue* obj, int x) {
    STPush(&obj->pushst,x);
}

int myQueuePop(MyQueue* obj) {
   int front = myQueuePeek(obj);
   STPop(&obj->popst);
   return front;
}

int myQueuePeek(MyQueue* obj) {
    if(STEmpty(&obj->popst))
    {
       while(!STEmpty(&obj->pushst))
       {
          STPush(&obj->popst,STTop(&obj->pushst));
          STPop(&obj->pushst);
       }
    }

    return STTop(&obj->popst);
}

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->popst) && STEmpty(&obj->pushst);
}

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->popst);
    STDestroy(&obj->pushst);

    free(obj); 
}

/**
 * Your MyQueue struct will be instantiated and called as such:
 * MyQueue* obj = myQueueCreate();
 * myQueuePush(obj, x);
 
 * int param_2 = myQueuePop(obj);
 
 * int param_3 = myQueuePeek(obj);
 
 * bool param_4 = myQueueEmpty(obj);
 
 * myQueueFree(obj);
*/

队列

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为 队尾
出队列:进行删除操作的一端称为 队头

队列也可以顺序表和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

链表实现队列

Queue.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>

typedef int QDataType;
typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);

Queue.c

#include"Queue.h"

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}

	newnode->val = x;
	newnode->next = NULL;

	if (pq->ptail == NULL)
	{
		pq->ptail = pq->phead = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}

	pq->size++;
}

void QueuePop(Queue* pq)
{
	assert(pq);
	 
	assert(pq->phead);

	QNode* del = pq->phead;
	pq->phead = pq->phead->next;
	free(del);
	del = NULL;

	if (pq->phead == NULL)
		pq->ptail = NULL;

	pq->size--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	 
	assert(pq->phead);

	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	 
	assert(pq->ptail);

	return pq->ptail->val;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->phead == NULL;
}

int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}

text.c

#include"Queue.h"
void menu() {
	printf("******************队列**********************\n");
	printf("******1、入队          2、出队**************\n");
	printf("******3、打印队头元素***********************\n");
	printf("******4、打印队尾元素***********************\n");
	printf("******5、打印全部队列元素*******************\n");
	printf("******6、判断队列是否为空*******************\n");
	printf("******7、打印队列元素个数*******************\n");
}
int main()
{
	Queue q;
	QueueInit(&q);
	int op;
	QDataType x;

	do {
		menu();
		printf("请选择您的操作:\n");
		scanf("%d", &op);
		switch (op)
		{
		case 1:
			printf("请输入队列的数据:\n");
			scanf("%d", &x);
			QueuePush(&q,x);
			break;
		case 2:
			QueuePop(&q);
			break;
		case 3:
			printf("%d\n", QueueFront(&q));
			break;
		case 4:
			printf("%d\n", QueueBack(&q));
			break;
		case 5:
			while (!QueueEmpty(&q))
			{
				printf("%d ", QueueFront(&q));
				QueuePop(&q);
			}
			printf("\n");
			break;
		case 6:
			if (QueueEmpty(&q))
				printf("队列为空\n");
			else
			{
				printf("队列不为空\n");
			}
			break;
		case 7:
			printf("%d\n", QueueSize(&q));
			break;
		case 0:
			printf("goodby");
			break;
		default:
			printf("您的输入有误,请重新输入\n");
			break;
		}
	}while (op);	
	QueueDestroy(&q);

	return 0;
}

相关例题

注意:

  • 你只能使用队列的基本操作 —— 也就是 push to backpeek/pop from frontsize 和 is empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
typedef int QDataType;
typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}

	newnode->val = x;
	newnode->next = NULL;

	if (pq->ptail == NULL)
	{
		pq->ptail = pq->phead = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}

	pq->size++;
}

void QueuePop(Queue* pq)
{
	assert(pq);
	 
	assert(pq->phead);

	QNode* del = pq->phead;
	pq->phead = pq->phead->next;
	free(del);
	del = NULL;

	if (pq->phead == NULL)
		pq->ptail = NULL;

	pq->size--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	 
	assert(pq->phead);

	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	 
	assert(pq->ptail);

	return pq->ptail->val;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->phead == NULL;
}

int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}




typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&pst->q1);
    QueueInit(&pst->q2);

    return pst;
}

void myStackPush(MyStack* obj, int x) {
    if(!QueueEmpty(&obj->q1))
    {
      QueuePush(&obj->q1,x);
    }
    else
    {
      QueuePush(&obj->q2,x);
    }
}

int myStackPop(MyStack* obj) {
    Queue* emptyq = &obj->q1;
    Queue* nonemptyq = &obj->q2;
 
  if(!QueueEmpty(&obj->q1)) 
  {
      emptyq = &obj->q2;
      nonemptyq = &obj->q1;
  }
while(QueueSize(nonemptyq)>1)
{
   QueuePush(emptyq,QueueFront(nonemptyq));
   QueuePop(nonemptyq);
}
int top =QueueFront(nonemptyq);
QueuePop(nonemptyq);

return top;
}

int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);

    free(obj);
}

/**
 * Your MyStack struct will be instantiated and called as such:
 * MyStack* obj = myStackCreate();
 * myStackPush(obj, x);
 
 * int param_2 = myStackPop(obj);
 
 * int param_3 = myStackTop(obj);
 
 * bool param_4 = myStackEmpty(obj);
 
 * myStackFree(obj);
*/

实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型
时可以就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。

    ​​​​​

补充方法:

 

如何计算循环队列的数据个数:

(back +(k+1)- front)%(k+1)

感谢阅读!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你好,赵志伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值