数据结构栈和队列完整代码复习

简介: 引言:一、栈的完整代码1.头文件:2.接口实现文件:3.测试文件:4.测试样列:二、队列的完整代码1.头文件:2.接口实现文件:3.测试文件:4.测试样列:三、总结:

引言:

在我的全面信息查找的情况下,并没有找到我想要的二叉树的课程,所以咱们接下来要朝刷有关数据结构的题目这一块进军了,等我题目玩的差不多,我们再开始二叉树的学习


一、栈的完整代码

1.头文件:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
//这边还是不要管你下午睡了多久,现在可以把栈自己实现一遍是最重要的
//首先要理解栈的特性,然后第一步就是定义出它的结构体(并且改进一下结构体而已)
typedef int STDataType;
typedef struct Stack
{
  STDataType* data;
  //定义完这两个不要懵,其实答案就在眼前(因为需要使你的栈空间是一个动态的东西,所以这边……)
  int top;
  int capacity;
}ST;
//弄完了结构体我们现在就要弄几个主要的接口函数
//首先第一个应该是
//初始化
void StackInit(ST* ps);
//销毁
void StackDestory(ST* ps);
//栈顶插入
void StackPush(ST* ps, STDataType x);
//栈顶删除
void StackPopt(ST* ps);
//寻找栈顶(这个肯定是有返回值的)
STDataType StackTop(ST* ps);
//还有一个就是计算栈的大小
int StackSize(ST* ps);
//判断栈是否为空
bool StackEmpty(ST* ps);

2.接口实现文件:

#include"Stack.h"
//初始化(错误写法)
//void StackInit(ST* ps)
//{
//  //STDataType* data = NULL;  这边怎么敢这样子写的啊
//  ps->data = NULL;
//  //知道了有初始化这个接口,就成功了三分之一了,所以我们不要怕,现在就只是实现一下而已
//  int capacity = 0;
//  int top = 0;//此时这个top的表示会影响到top的位置(因为我们是使用下标来实现我们的栈,座椅下标是从0开始的)
//
//}
void StackInit(ST* ps)//正确的写法
{
  assert(ps);
  ps->data = NULL;
  //这个位置top给0,表示top此时指向的是栈顶数据的下一个
  //这个位置top给-1,表示top此时指向的是栈顶数据(就是下标原理:放一个数据top加1,此时-1加1等于0,此时就是我的数据的第一个数据,下标为0,如果top是0,top加1,下标为1,此时top就是表示第二个数据,所以是栈顶数据的下一个)
  ps->top = 0;//这个位置也可以把ps->top = -1;看我自己(都可以只是表示的意思不一样而已)
  ps->capacity = 0;
}
//销毁
void StackDestory(ST* ps)
{
  //销毁是一个技术活,此时想要销毁就要格外的注意了(好像不要注意)
  free(ps->data);
  ps->data = NULL;
  ps->capacity = 0;
  ps->top = 0;
}
//栈顶插入
void StackPush(ST* ps, STDataType x)
{
  assert(ps);
  //此时想要对栈顶进行一个插入,首先肯定要有一块空间给我,不然我插个屁,并且我在进行插入操作的时候一定要对其进行检查空间是否还有
  if (ps->capacity == ps->top)//此时是我的top在往后走,不是我的data,data只是一个存的,所以千万不敢写成if (ps->capacity == ps->data)
  {
    /*ST* newcapacity = ps->capacity == 0 ? 4 : newcapacity;*/
    //int newCapacity = ps->capacity == 0 ? 4 : newCapacity;//这句已经是写对了百分之90,但是就是有那么一点的细节没有写明白,就是一定能够要理解此时的capacity是一个int类型的数据,所以newcapacity也应该是一个int类型的数据 
    int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//这步要重点注意,不敢写错掉
    /*ST* tmp = (ST*)realloc(ps->data, sizeof(ST)* newCapacity);*/
    STDataType* tmp = (STDataType*)realloc(ps->data, sizeof(STDataType) * newCapacity);//这句本来也是写对了百分之90,但是也是还有点没有注意到(就是此时你开辟的空间是int类型的空间(这边就千万不敢和链表开辟一个结构体的空间那边弄混掉,所以此时这个写成int的大小就行))
    //这边你居然把你最拿手的动态内存的开辟的检查给忘记掉了
    if (tmp == NULL)
    {
      printf("realloc fail\n");
      exit(-1);
    }
    //程序来到这里就是表示成功了
    ps->data = tmp;
    ps->capacity = newCapacity;
  }
  //有了新空间
  /*ps->top = x;*/
  ps->data[ps->top] = x;//这步值得表扬一下,首先你是知道是应该要在栈顶存放数据的,但是你不应该忘记了是在那个结构体数据中的栈顶
  ps->top++;//这个就是表示我的数据开始向后走,并且我的首个结构体中的那个top就是我最后出的数据,也就是栈底的数据
}
//栈顶删除
void StackPopt(ST* ps)
{
  assert(ps);
  assert(ps->top > 0);
  /*while*/ //这边不敢想出写while循环了我的爷,这个已经不是链表了,这个是栈,这边进行删数据是最简单的,只需要把栈头给删掉就行了
  //free(ps->top);
  //ps->top = NULL;
  //这边也不敢这样子写,因为我哪里来的指针,还置成空指针,你那里想出来的高级东西(还是那句话,不敢搞混掉,这个是栈数组不是链表),并且没有指针,这个是一个数组而已
  //所以正确的栈的删除的写法应该是,只需要下面这步就行:(前提是栈中有数据)
  ps->top--;//其实这个就是表示删除数据了
  //但是写到了这里,我们不敢太得意,我们一定要再仔细思考一下(特别是在删除数据的时候),所以一定要再这上面加一个判断条件
}
//寻找栈顶
STDataType StackTop(ST* ps)
{
  assert(ps);
  assert(ps->top > 0);
  //return ps->top - 1;//这边寻找直接写这个肯定是没有任何关系,但是一点要注意top的初始化是0还是-1;
  //但是还是写错了一点点(这边我们肯定是不能这样写的(因为这样写的意思代表的就只是我后面动态开辟出来的数据)),我因该要按照下面这样写
  return ps->data[ps->top - 1];//为什么我要这样写呢?原因是我是用的一个数组来进行对栈的创建,所以当我们要寻找栈的数据时(就要把这个当成一个下标来使用,不敢还是跟链表弄混掉)
  //注意点就是要把后面创建的数据用下标来联系起来(并且注意top的下标就是0)
}
//判断栈是否为空
bool StackEmpty(ST* ps)
{
  //if (ps->top == 0)
  //{
  //  return true;
  //}
  //else
  //{
  //  return false;
  //}
  //或者可以这样写:直接return
  return ps->top == 0;
}
int StackSize(ST* ps)
{
  return ps->top;//这边就要明白此时的这个ps->top,不是ps->data[ps->top],这两个是有区别的,一个表示的是头元素,一个是在加加后得到的,此时这个ps->top,此时通过一直的加加,现在它就是在我的栈底了,所以它就可以代表我的数据的个数
}

3.测试文件:

#include"Stack.h"
void Test()
{
  ST p;
  //初始化
  StackInit(&p);
  //栈顶插
  StackPush(&p, 1);
  StackPush(&p, 2);
  StackPush(&p, 3);
  StackPush(&p, 4);
  StackPush(&p, 5);
  //栈顶删除
  StackPopt(&p);
  printf("%d ", StackTop(&p));
  printf("%d ", StackSize(&p));
  printf("%d ", StackEmpty(&p));
  //插入删除之后,这边我一定要有一步遍历栈,然后打印出来
  while (!StackEmpty(&p))
  {
    /*printf("%d ",p->data[p->top-1]);*/
    printf("%d ", StackTop(&p));//一个是调函数一个是不调函数,都一样
    //打印完之后,一定要把栈顶给删除掉,我们才可以进行下一个栈顶的打印
    StackPopt(&p);
  }
  StackDestory(&p);
}
int main()
{
  Test();
  return 0;
}


4.测试样列:

9.png


二、队列的完整代码

1.头文件:

#pragma once
//刚刚在几个的转折之下我们终于是完成了栈的数组实现
//现在我们来看一下什么是队列OK;
//首先话不多说,咱结构体走起(使用链表的形式实现我的队列)
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct QueueNewnode
{
  struct Newnode* next;
  STDataType data;//这个数据自然而然是一个类型(怎么可能是一个结构体类型(数据这边千万不敢当傻子,搞一个结构体的类型出来))
}QueueNode;
typedef struct Queue
{
  QueueNode* tail;
  QueueNode* head;
}Queue;
//结构体创建好了,现在就轮到各个接口的实现了
//初始化
void QueueInist(Queue* ps);
//销毁
void QueueDestory(Queue* ps);
//插入结点
void QueuePush(Queue* ps,STDataType x);
//删除结点
void QueuePopt(Queue* ps);
//队列的大小计算
size_t QueueSize(Queue* ps);//这个也是有返回值的
//判断是否为空
bool QueueEmpty(Queue* ps);
//但是要注意的是找队列头和找队列尾,一定要有返回值哦
//找队列尾
//void QueueBack(Queue* ps);
找队列头
//void QueueFront(Queue* ps);
//你反回的也不是一个结构体啊,你这边怎么敢写成结构体的啊(返回类型直接写int类型不就行了吗,我真的是人才)
//QueueNode QueueBack(Queue* ps);
//QueueNode QueueFront(Queue* ps);
STDataType QueueBack(Queue* ps);
STDataType QueueFront(Queue* ps);

2.接口实现文件:

#include"Queue.h"
//有了这些
//初始化
void QueueInist(Queue* ps)//正确
{
  assert(ps);
  //初始化如果不出意外的话应该是最简单的,只要有两个空指针应该就搞定了吧
  ps->head = NULL;
  ps->tail = NULL;
  //好像就是这样
}
//销毁
void QueueDestory(Queue* ps)//正确
{
  assert(ps);
  //我刚刚充分意识到了栈的空间的销毁的简单(因为我是通过数组实现的栈)
  //然而此时我用的是链表的形式(首先肯定就要知道这个是没有那么简单的,所以我们得仔细思考)
  while (ps->head != NULL)
  {
    Queue* next = ps->head->next;
    free(ps->head);
    ps->head = NULL;
    ps->head = next;
  }
  //此时的我新增的结点是倒是全部都销毁了,但是要记得把第二个结构体中的指针给置成空指针(这样是最好的)
  ps->head = NULL;
  ps->tail = NULL;
}
//插入结点   
void QueuePush(Queue* ps,STDataType x)//大致正确(判断条件处理的不是很好)
{
  assert(ps);
  //此时的这个插入一定要结合好队列的特性,不然就不好写(先进先出)
  //首先我们要有一个新结点
  QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
  //有了这个新结点(就根据特性进行插入)(是在尾的地方进行插入,这点要明白)
  newnode->data = x;
  newnode->next = NULL;
  //if (ps->head == ps->tail)
  //if (ps->tail == NULL)
  //判断无的条件,并不需要如上这样写,直接写下面这个就行了
  if (ps->head == NULL)
  {
    //这个条件就是表示队列中无数据(无数据,我们就只要进行赋值操作就可以完成我想要的)
    ps->head = newnode;
    ps->tail = newnode;
  }
  else
  {
    ps->tail->next = newnode;
    ps->tail = newnode;
    newnode->next = NULL;
    //写完基本的之后就要进行注意点的注意
  }
}
//删除结点
void QueuePopt(Queue* ps)//正确
{
  assert(ps);
  assert(!QueueEmpty(ps));//这个断言就是保证队列不为空,我才进行删除操作
  if (ps->head != NULL)
  {
    Queue* next = ps->head->next;
    free(ps->head);
    ps->head = NULL;
    ps->head = next;
  }
  else
  {
    ps->tail = NULL;//这步就是表示我已经把队列给删除完了,但是此时的tail并没有置成一个NULL,所以此时的tail就是一个野指针,所以一定要把tail也给释放掉
  }
}
//队列的大小计算
size_t QueueSize(Queue* ps)//错误
{
  assert(ps);
  /*return ps->head->data;*/
  //这边就小瞧了队列的数据个数计算了
  //要区分开来
  //因为这个是一个链表,所以只要是你想要遍历数据(就一定要使用循环,不用循环是不可能拿到链表中的所有数据的)
  int n = 0;
  QueueNode* cur = ps->head;
  while (cur != NULL)
  {
    n++;
    cur = cur->next;
  }
  //这边完成了上述的所有的步骤,这边不敢忘记掉你写这个函数的目的,目的就是:计算这个队列的大小:所以最后一定还要记得把返回值给返回去
  return n;
 }
//判断是否为空
bool QueueEmpty(Queue* ps)
{
  assert(ps);
  //if (ps->head)
  //{
  //  return true;
  //}
  //else
  //{
  //  return false;
  //}
  //这边就不是按照栈的那个写法来判断队列是否为空了,这边是通过下面这个方法:(但是一写完,我发现我的方法好像也还是可以的)
  return ps->head == NULL;
}
STDataType QueueBack(Queue* ps)//差一点点就完全正确了
{
  assert(ps);
  assert(!QueueEmpty(ps));
  return ps->tail->data;
}
STDataType QueueFront(Queue* ps)
{
  assert(ps);
  assert(!QueueEmpty(ps));
  return ps->head->data;
}

3.测试文件:

#include"Queue.h"
void Test1()
{
  Queue* ps;
  //初始化
  QueueInist(&ps);
  //插入数据
  QueuePush(&ps, 1);
  QueuePush(&ps, 2);
  QueuePush(&ps, 3);
  QueuePush(&ps, 4);
  QueuePush(&ps, 5);
  QueuePush(&ps, 6);
  QueuePush(&ps, 7);
  QueuePush(&ps, 8);
  QueuePush(&ps, 9);
  QueuePush(&ps, 10);
  //队列大小的计算
  printf("%d\n ", QueueSize(&ps));
  //判断是否为空
  printf("%d\n ", QueueEmpty(&ps));
  //队列尾数据
  printf("%d\n ", QueueBack(&ps));
  //队列头数据
  printf("%d\n ", QueueFront(&ps));
  //删除
  QueuePopt(&ps);
  QueuePopt(&ps);
  QueuePopt(&ps);
  //这边来一个遍历数据,进行打印
  //while (cur != NULL)
  //{
  //  printf("%d",cur->data);//这边这样写你就是把这个东西给当成是一个链表了,但是这个东西是一个队列,不是链表,所以 这边一定不敢这样写,这样写就是代表从前向后读取数据了,就违背了队列的特性了
  //  cur = cur->next;
  //}
  //QueueNode* cur = ps->head;
  //while (QueueEmpty(&ps))//这个写法也是有大问题的
  //{
  //  printf("%d ", QueueFront(&ps));
  //  QueuePopt(&ps);//并且你这边千万不敢把这个删除数据给忘了,不然你就不可能拿到下一个数据了
  //}
  //printf("\n");
  while (!QueueEmpty(&ps))
  {
    STDataType front = QueueFront(&ps);//表示先取最头上的数据
    printf("%d ", front);
    QueuePopt(&ps);//取完此时的最头上的这个数据之后就一定还要把它给删掉,这样我就可以拿到下一个数据了,不然就不可以遍历整个队列了
  }
  printf("\n");
  //销毁
  QueueDestory(&ps);
}
int main()
{
  Test1();
  return 0;
}

4.测试样列:

10.png


三、总结:

所以我们应该要多写,自己写出来的才是自己的哦!

相关文章
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
26 1
|
18天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
39 5
|
16天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
43 1
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
25天前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
42 0
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
159 9
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
51 4
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
43 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!

热门文章

最新文章