C语言---数据结构实验---数制转换---表达式求值---回文判断---二叉树创建遍历

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: C语言---数据结构实验---数制转换---表达式求值---回文判断---二叉树创建遍历

写在前面

数据结构的实现是多种多样的,在本篇实现多种数据结构的过程中会尽可能的使用动态内存的形式,避免使用宏定义的形式,宏定义的形式是很老旧的版本,在实际运用中很少使用,掌握动态运用内存是必备的技能

数据结构:栈和队列的实现以及二者相互实现

对于二叉树的遍历创建方法有多种多样,这里使用的是leetcode等平台力荐的递归形式,递归完成二叉树遍历是较为标准和简单的方式

如果对二叉树的遍历不熟悉,最好优先复习二叉树是如何进行递归遍历和创建的

数据结构—手撕图解二叉树

assert函数仅仅是编写代码时便于调试所加,可以删除,不会造成影响

下载链接

实验三Gitee

实验四Gitee

数制转换

问题描述

将十进制数N和其他d进制数之间进行转换是计算机实现计算的基本问题,解决方案很多,其中最简单的方法是除d取余法。例如,(1348)10=(2504)8,其转化过程如下所示:

N             N div 8            N mod 8
         1348            168                4
         168             21                 0
         21              2                  5
         2               0                  2

从中可以看出,最先产生的余数4是转换结果的最低位,这正好符合栈的“后进先出”的特性。所以可以用顺序栈来模拟这个过程。

题目解析

很简单的题,写一个栈入余数即可

需要注意的是,超过十进制的数有字母的参与,因此可以提前写一个数组,然后把栈内元素当成下标,再用下标元素访问数组内元素,就可以达到输出数字和字母的效果

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//1. 将十进制数N和其他d进制数之间进行转换是计算机实现计算的基本问题,解决方案很多,其中最简单的方法是除d取余法。
// 例如,(1348)10 = (2504)8,其转化过程如下所示:
//N             N div 8            N mod 8
//1348            168                4
//168             21                 0
//21              2                  5
//2               0                  2
//从中可以看出,最先产生的余数4是转换结果的最低位,这正好符合栈的“后进先出”的特性。所以可以用顺序栈来模拟这个过程。
typedef int STDataType;
typedef struct Stack
{
  STDataType* a;
  int capacity;
  int top;
}Stack;
void StackInit(Stack* pst)
{
  pst->a = (STDataType*)malloc(sizeof(STDataType) * 4);
  if (pst->a == NULL)
  {
    perror("malloc fail");
    return;
  }
  pst->capacity = 4;
  pst->top = 0;
}
STDataType StackTop(Stack* pst)
{
  assert(pst);
  assert(pst->top);
  return pst->a[pst->top - 1];
}
void StackPop(Stack* pst)
{
  assert(pst);
  assert(pst->top);
  pst->top--;
}
void StackPush(Stack* pst, STDataType x)
{
  assert(pst);
  if (pst->capacity = pst->top)
  {
    STDataType* tmp = NULL;
    int newcapacity = pst->capacity * 2;
    tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
    if (tmp == NULL)
    {
      perror("realloc fail");
      return;
    }
    pst->a = tmp;
    pst->capacity = newcapacity;
  }
  pst->a[pst->top] = x;
  pst->top++;
}
bool StackEmpty(Stack* pst)
{
  if (pst->top == 0)
    return true;
  else
    return false;
}
//被除数 dividend 
//除数   divisor 
//商     result
//余数   remainder
void Calculate(Stack* pst, int dividend, int divisor)
{
  int remainder;
  while (dividend)
  {
    remainder = dividend % divisor;
    StackPush(pst, remainder);
    dividend = dividend / divisor;
  }
}
void Print(Stack* pst, int dividend, int divisor)
{
  char array[16] = { '0', '1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
  printf("%d(10)=", dividend);
  while (!StackEmpty(pst))
  {
    printf("%c", array[StackTop(pst)]);
    StackPop(pst);
  }
  printf("(8)\n");
}
int main()
{
  int dividend = 1348;
  printf("输入十进制数->");
  scanf("%d", &dividend);
  int divisor = 8;
  printf("输入要改变的进制数->");
  scanf("%d", &divisor);
  Stack st;
  StackInit(&st);
  Calculate(&st, dividend, divisor);
  Print(&st, dividend, divisor);
  return 0;
}

表达式求值

题目描述

从键盘输入一个算术表达式并输出它的结果,算术表达式可包含加、减、乘、除、十进制整数和小括号,利用栈实现。

题目解析

在解决问题前要先明确前缀表达式,中缀表达式,后缀表达式的概念:

中缀表达式:

通常来说在日常中遇到最多的就是中缀表达式,例如:

( 2 + 3 ) × 4 - 5

前缀表达式:

前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前:

例如:中缀表达式 ( 2 + 3 ) × 4 - 5,采用前缀表达式为:- × + 2 3 4 5

后缀表达式:

例如:中缀表达式 ( 2 + 3 ) × 4 - 5,采用后缀表达式为:2 3 4 5 + × -

在知晓了三个表达式的概念后再看题目,题目中的要求其实就是,给定一个中缀表达式,要求将它转换成一个后缀表达式,再利用栈的原理来解决,那么就需要完成两个工作,如何将中缀表达式转换成后缀表达式?如何将后缀表达式借助栈计算出具体的结果?

中缀表达式转换为后缀表达式

实现操作:

  • 对于操作数来说:

直接进行输出即可

  • 对于操作符来说
  1. 如果栈为空,则进行入栈的操作
  2. 与栈顶元素进行比较,如果优先级比栈顶的操作符的优先级高,则进行入栈操作
  3. 与栈顶元素进行比较,如果优先级比栈顶的操作符的优先级低,则进行出栈顶操作符操作
  • 出栈所有的操作符
  • 循环上面的步骤直到没有操作符

下面用一个例子来解释这个操作的原理

如何利用后缀表达式计算结果

  1. 操作数入栈
  2. 操作符,取栈顶的两个操作数运算,运算结果再入栈

对于带左右括号的情况又如何解决?可以转换为递归的子问题来处理,当遇到右括号的时候为出栈条件之后再进行上面的步骤即可

本题由于较复杂,使用STL较为方便,因此这里使用C++来处理

#include <bits/stdc++.h>
using namespace std;
int cal(int a, int b, char opera)
{
  switch (opera)
  {
  case '+': return a + b;
  case '-': return a - b;
  case '*': return a * b;
  case '/': return a / b;
  default: throw invalid_argument("bad opera");
  }
}
int calculate(string s)
{
  string tmp;
  for (char i : s)
  {
    if (i != ' ')
    {
      tmp.push_back(i);
    }
  }
  s = std::move(tmp);
  stack<int> result;
  stack<char> operas;
  operas.push('+');
  result.push(0);
  for (int i = 0; i < s.size();)
  {
    if (s[i] >= '0' && s[i] <= '9')
    {
      operas.push('+');
      int val = 0;
      while (s[i] >= '0' && s[i] <= '9')
      {
        val = val * 10 + (s[i] - 48);
        i++;
      }
      result.push(val);
    }
    else if (s[i] == '(')
    {
      operas.push('+');
      result.push(-1);
      i++;
    }
    else if (s[i] == ')')
    {
      int val = 0;
      while (result.top() != -1)
      {
        val = cal(val, result.top(), operas.top());
        result.pop(); 
        operas.pop();
      }
      if (operas.top() == '*' || operas.top() == '/')
      {
        result.pop();
        val = cal(result.top(), val, operas.top());
        operas.pop();
      }
      if (val >= 0)
      {
        result.top() = val;
      }
      else
      {
        result.top() = -val;
        if (operas.top() == '+')
        {
          operas.top() = '-';
        }
        else operas.top() = '+';
      }
      i++;
    }
    else
    {
      char opera = s[i]; i++;
      if (s[i] == '(')
      {
        result.push(-1); i++;
        operas.push(opera);
      }
      else
      {
        int val = 0;
        while (s[i] >= '0' && s[i] <= '9')
        {
          val = val * 10 + (s[i] - 48);
          i++;
        }
        if (opera == '*' || opera == '/')
        {
          result.top() = cal(result.top(), val, opera);
        }
        else
        {
          operas.push(opera);
          result.push(val);
        }
      }
    }
  }
  int val = 0;
  while (!result.empty())
  {
    val = cal(val, result.top(), operas.top());
    result.pop(); operas.pop();
  }
  return val;
}
int main()
{
  //string s = "(1+(4+5+2)-3)+(6+8)*2";
  string s;
  cout << "输入中缀表达式,例如(1+(4+5+2)-3)+(6+8)*2" << endl;
  cin >> s;
  cout << calculate(s) << endl;
  return 0;
}

回文判断

题目描述

假设称正读和反读都相同的字符序列为“回文”,例如,’abba’和’abcba’是回文,’abcde’和’ababab’则不是回文。请编写一个程序判别读入的一个以’@’为结束符的字符序列是否是“回文”。提示:由于依次输入的字符序列中不含特殊的分隔符,则在判别是否是“回文”时,一种比较合适的做法是,同时利用“栈”和“队列”两种结构。

题目解析

本题也很简单,创建队列和栈两个数据结构,分别取Top比较再Pop,放到while循环里即可

//3. 假设称正读和反读都相同的字符序列为“回文”,例如,’abba’和’abcba’是回文,’abcde’和’ababab’则不是回文。
//请编写一个程序判别读入的一个以’@’为结束符的字符序列是否是“回文”。
//提示:由于依次输入的字符序列中不含特殊的分隔符,则在判别是否是“回文”时,一种比较合适的做法是,同时利用“栈”和“队列”两种结构。\
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef char QueueDataType;
typedef struct QNode
{
  QueueDataType data;
  struct QNode* next;
}QNode;
typedef struct Queue
{
  QNode* phead;
  QNode* ptail;
}Queue;
void QueueInit(Queue* pq)
{
  pq->phead = NULL;
  pq->ptail = NULL;
}
QNode* BuynewQNode(QueueDataType x)
{
  QNode* newnode = (QNode*)malloc(sizeof(QNode));
  if (newnode == NULL)
  {
    perror("malloc fail");
    return NULL;
  }
  newnode->data = x;
  newnode->next = NULL;
  return newnode;
}
void QueuePush(Queue* pq, QueueDataType x)
{
  assert(pq);
  QNode* newnode = BuynewQNode(x);
  if (pq->phead == NULL)
  {
    pq->phead = pq->ptail = newnode;
  }
  else
  {
    pq->ptail->next = newnode;
    pq->ptail = newnode;
  }
}
void QueuePop(Queue* pq)
{
  assert(pq);
  assert(pq->phead);
  pq->phead = pq->phead->next;
}
QueueDataType QueueTop(Queue* pq)
{
  assert(pq);
  assert(pq->phead);
  return pq->phead->data;
}
bool QueueEmpty(Queue* pq)
{
  assert(pq);
  if (pq->phead == NULL)
  {
    return true;
  }
  else
  {
    return false;
  }
}
typedef char STDataType;
typedef struct Stack
{
  STDataType* a;
  int capacity;
  int top;
}Stack;
void StackInit(Stack* pst)
{
  pst->a = (STDataType*)malloc(sizeof(STDataType) * 4);
  if (pst->a == NULL)
  {
    perror("malloc fail");
    return;
  }
  pst->capacity = 4;
  pst->top = 0;
}
STDataType StackTop(Stack* pst)
{
  assert(pst);
  assert(pst->top);
  return pst->a[pst->top - 1];
}
void StackPop(Stack* pst)
{
  assert(pst);
  assert(pst->top);
  pst->top--;
}
void StackPush(Stack* pst, STDataType x)
{
  assert(pst);
  if (pst->capacity = pst->top)
  {
    STDataType* tmp = NULL;
    int newcapacity = pst->capacity * 2;
    tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
    if (tmp == NULL)
    {
      perror("realloc fail");
      return;
    }
    pst->a = tmp;
    pst->capacity = newcapacity;
  }
  pst->a[pst->top] = x;
  pst->top++;
}
bool StackEmpty(Stack* pst)
{
  if (pst->top == 0)
    return true;
  else
    return false;
}
void Input(Queue* pq, Stack* ps)
{
  char ret;
  printf("输入回文字符,以@结尾->");
  while (1)
  {
    scanf("%c", &ret);
    if (ret == '@')
      break;
    QueuePush(pq, ret);
    StackPush(ps, ret);
  }
}
void Judge(Queue* pq, Stack* ps)
{
  while (!QueueEmpty(pq))
  {
    char que = QueueTop(pq);
    QueuePop(pq);
    char st = StackTop(ps);
    StackPop(ps);
    if (que!=st)
    {
      printf("不是回文\n");
      return;
    }
  }
  printf("是回文\n");
  return;
}
int main()
{
  Queue q;
  Stack s;
  QueueInit(&q);
  StackInit(&s);
  Input(&q, &s);
  Judge(&q, &s);
  return 0;
}

二叉树的创建、遍历及其它基本操作的实现

问题描述

  1. 以二叉链表作存储结构创建如下二叉树:

  1. 输出二叉树的中序遍历序列和后序遍历序列,以验证所建二叉树的正确性;
  2. 按二叉树的层次输出所建二叉树各层的结点,要求同层的结点自左向右排列。(提示:用到两个队列P、Q。其中P存放当前层上的结点,Q存放下一层的结点。)

题目解析

本实验就是对二叉树的简单操作,熟悉二叉树即可

二叉树介绍链接:

数据结构—手撕图解二叉树

注意:

创建二叉树的方法有很多种,标准的创建二叉树的方法是用递归调用进行创建,基本原理可以在上文链接寻找

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
typedef struct BinaryTreeNode* QDataType;
typedef struct QNode
{
  QDataType data;
  struct QNode* next;
}QNode;
typedef struct Queue
相关文章
|
3月前
|
存储 算法 编译器
数据结构实验之矩阵的运算器(二维数组)
本实验旨在通过团队合作,掌握数组和矩阵相关运算的代码实现,包括矩阵的加减、数乘、转置、乘法、n次方及行列式的计算。实验过程中,成员们需分工协作,解决编程难题,最终实现一个功能完备的矩阵计算器。通过本实验,不仅锻炼了编程能力,还加深了对数学概念的理解,同时培养了团队合作精神。
89 4
|
3月前
数据结构实验之串模式匹配问题
本实验旨在掌握串模式匹配技术,通过创建文本文件、实现单词计数与定位功能,最终构建一个包含文件建立、单词统计与定位、程序退出等选项的主菜单,以增强对字符串处理的理解与应用能力。
82 4
|
3月前
|
算法
数据结构实验之最长公共子序列
本实验旨在通过编程实践帮助学生理解串的基本概念及求解最长公共子序列的算法。实验内容包括使用动态规划方法设计并实现算法,以找出给定两序列的最大公共子序列。示例代码展示了如何通过构建状态矩阵和回溯路径来找到解决方案。实验总结指出,`memset()`函数用于内存初始化,且对于特定输入,程序能正确输出最长公共子序列之一。
75 4
|
3月前
|
算法
数据结构实验之操作系统打印机管理器问题
本实验旨在通过实现操作系统中的打印机管理器问题,掌握队列的基本操作如入队、出队等,利用队列的先进先出特性解决先申请先打印的问题。实验包括队列的初始化、入队、出队、打印队列内容等功能,并通过菜单式界面进行交互。实验结果显示基本功能可正常执行,但在连续操作时存在执行失败的情况,需进一步优化。
64 4
|
3月前
|
存储 算法 Perl
数据结构实验之链表
本实验旨在掌握线性表中元素的前驱、后续概念及链表的建立、插入、删除等算法,并分析时间复杂度,理解链表特点。实验内容包括循环链表应用(约瑟夫回环问题)、删除单链表中重复节点及双向循环链表的设计与实现。通过编程实践,加深对链表数据结构的理解和应用能力。
81 4
|
1月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
52 2
|
1月前
|
C语言
【C语言程序设计——入门】基本数据类型与表达式(头歌实践教学平台习题)【合集】
这份文档详细介绍了编程任务的多个关卡,涵盖C语言的基础知识和应用。主要内容包括: 1. **目录**:列出所有关卡,如`print函数操作`、`转义字符使用`、`数的向上取整`等。 2. **各关卡的任务描述**:明确每关的具体编程任务,例如使用`printf`函数输出特定字符串、实现向上取整功能等。 3. **相关知识**:提供完成任务所需的背景知识,如格式化输出、算术运算符、关系运算符等。 4. **编程要求**:给出具体的代码编写提示。 5. **测试说明**:包含预期输入输出,帮助验证程序正确性。 6. 文档通过逐步引导学习者掌握C语言的基本语法和常用函数,适合初学者练习编程技能。
46 1
|
1月前
|
数据采集 存储 算法
【C++数据结构——图】图的遍历(头歌教学实验平台习题) 【合集】
本文介绍了图的遍历算法,包括深度优先遍历(DFS)和广度优先遍历(BFS)。深度优先遍历通过递归方式从起始节点深入探索图,适用于寻找路径、拓扑排序等场景;广度优先遍历则按层次逐层访问节点,适合无权图最短路径和网络爬虫等应用。文中提供了C++代码示例,演示了如何实现这两种遍历方法,并附有测试用例及结果,帮助读者理解和实践图的遍历算法。
46 0
|
3月前
|
存储 算法 C语言
C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项
本文深入探讨了C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项,并通过案例分析展示了实际应用,旨在帮助读者提高编程效率和代码质量。
185 4
|
3月前
|
机器学习/深度学习 存储 算法
数据结构实验之二叉树实验基础
本实验旨在掌握二叉树的基本特性和遍历算法,包括先序、中序、后序的递归与非递归遍历方法。通过编程实践,加深对二叉树结构的理解,学习如何计算二叉树的深度、叶子节点数等属性。实验内容涉及创建二叉树、实现各种遍历算法及求解特定节点数量。
131 4

热门文章

最新文章