【奇妙的数据结构世界】 用经典例题对数组进行全面分析 | C++

简介: 简单来说,数据结构是一种辅助程序设计并且进行优化的方法论,它不仅讨论数据的存储与处理的方法,同时也考虑到了数据彼此之间的关系与运算,从而极大程度的提高程序执行的效率,减少对内存空间的占用等。不同种类的数据结构适用于不同的程序应用,选择合适正确的数据结构,可以让算法发挥出更大的性能,给设计的程序带来更高效率的算法。

前言

       简单来说,数据结构是一种辅助程序设计并且进行优化的方法论,它不仅讨论数据的存储与处理的方法,同时也考虑到了数据彼此之间的关系与运算,从而极大程度的提高程序执行的效率,减少对内存空间的占用等。不同种类的数据结构适用于不同的程序应用,选择合适正确的数据结构,可以让算法发挥出更大的性能,给设计的程序带来更高效率的算法。

一、数组是什么?

1.简要介绍

  数组类型是一种典型的静态数据结构,它使用了连续分配的内存空间去存储数据内容。静态数据结构是在编译时就给其变量分配好一定大小的内存空间。在建立静态数据结构的初期,必须事先去声明可能要占用多大的固定内存空间,因此这样可能造成一定的内存浪费或是经过后续操作出现数据溢出的现象。当对于简单的程序设计问题时,我们可以利用其下标,充分的对每一个位置上的数据进行修改、读取和使用,但是如果进行删除或插入数据的操作时将会移动大量的数据元素。

2.具体情况

   数组是具有相同和数据类型的变量的集合,它们在内存中占有一块连续的内存空间。数组可以分为一维数组、二维数组和多维数组,平时的学习中一维和二维是常用的,多维数组的话一般就会涉及到一些复杂的空间问题。在如下的图一中,是一个一维数组array_1[7],它是拥有6个相同数据类型的数组。

二维数组可以视为一维数组的扩展,它与一维数组差别只在于维数的声明。在如下的图二中,是一个二维数组array_2[4][5]在直观平面上的具体排列方式。

  三维数组的表示法和二维数组一样,都可以视作一维数组的扩展。在如下的图三中,是一个三维数组array_3[2][3][4]将它想象成空间上的立方体的情况。

二、数组典型例题——一维&二维&三维

1.一维数组(校门外的树

①例题:


       某校大门外长度为 l 的马路上有一排树,每两棵相邻的树之间的间隔都是 1 米。我们可以把马路看成一个数轴,马路的一端在数轴 0 的位置,另一端在 l 的位置;数轴上的每个整数点,即 0、1、2、...、l,都种有一棵树。

       由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。


       输入要求:分析后可知需要输入马路的长度l,区域的数目m。m行的两个整数u和v,分别来表示一个区域的起点和终点坐标;


       输出要求:输出一个整数,表示移走每个区域上的树后剩余的树的数目;

   数据要求:1≤l≤10000、1≤m≤100、0≤u≤v≤l;

②代码展示:

#include<iostream>
using namespace std;
int tree_num[10001];
class tree {
public:
  int l,m;
  int u[101], v[101];
  void calculator()
  {
  for (int i = 0; i < m; i++)
  {
    for (int j = u[i]; j <= v[i]; j++)
    {
    tree_num[j] = 1;
    }
  }
  int count = 0;
  for (int k = 0; k <= l; k++)
  {
    if (tree_num[k] == 0)
    count++;
  }
  cout << "剩余" << count << "棵树" << endl;
  }
};
void text()
{
  tree t;
  cout << "请输入马路的长度:";
  cin >> t.l; 
  cout << "请输入区域的个数:";
  cin >> t.m;
  cout << "请开始分别输入" << t.m << "个区域的始点和终点坐标" << endl;
  for (int i = 0; i < t.m; i++)
  {
  cin >> t.u[i] >> t.v[i];
  }
  t.calculator();
}
int main()
{
  text();
}

③代码结果展示:

2.二维数组(彩票摇奖)

①例题:


       为了丰富人民群众的生活、支持某些社会公益事业,北塔市设置了一项彩票。该彩票的规则是:


1. 每张彩票上印有 7 个各不相同的号码,且这些号码的取值范围为 1~33。

2. 每次在兑奖前都会公布一个由七个各不相同的号码构成的中奖号码。

3. 共设置 7 个奖项,特等奖和一等奖至六等奖。


兑奖规则如下:

       - 特等奖:要求彩票上 7 个号码都出现在中奖号码中。

       - 一等奖:要求彩票上有 6 个号码出现在中奖号码中。

       - 二等奖:要求彩票上有 5 个号码出现在中奖号码中。

       - 三等奖:要求彩票上有 4 个号码出现在中奖号码中。

       - 四等奖:要求彩票上有 3 个号码出现在中奖号码中。

       - 五等奖:要求彩票上有 2 个号码出现在中奖号码中。

       - 六等奖:要求彩票上有 1 个号码出现在中奖号码中。


注:兑奖时并不考虑彩票上的号码和中奖号码中的各个号码出现的位置。例如,中奖号码为 23、31、1、14、19、17、18,则彩票 12、8、9、23、1、16、7由于其中有两个号码(23和1)出现在中奖号码中,所以该彩票中了五等奖。现已知中奖号码和小明买的若干张彩票的号码,请你写一个程序帮助小明判断他买的彩票的中奖情况。


       输入要求:输入的第一行只有一个自然数 n,表示小明买的彩票张数;第二行存放了 7 个介于 1 和 33 之间的自然数,表示中奖号码;在随后的 n 行中每行都有 7 个介于 1 和 33 之间的自然数,分别表示小明所买的 n 张彩票;


       输出要求:依次输出小明所买的彩票的中奖情况(中奖的张数),首先输出特等奖的中奖张数,然后依次输出一等奖至六等奖的中奖张数。

数据要求:1≤n<1000

②代码展示:

#include<iostream>
using namespace std;
int number[1001];
class lottery {
public:
  int n;
  int arr_1[7];
  int arr_2[1001][7];
  void calculator_1()
  {
  for (int i = 0; i < n; i++)
  {
    int count = 0;
    int ans = 0;
    while (ans < 7)
    {
    for (int j = 0; j < 7; j++)
    {
      if (arr_2[i][j] == arr_1[ans])
      count++;
    }
    ans++;
    }
    number[i] = count;
  }
  }
  void calculator_2()
  {
  int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0;
  for (int i = 0; i < n; i++)
  {
    switch (number[i])
    {
    case 1:
    g++;
    break;
    case 2:
    f++;
    break;
    case 3:
    e++;
    break;
    case 4:
    d++;
    break;
    case 5:
    c++;
    break;
    case 6:
    b++;
    break;
    case 7:
    a++;
    break;
    }
  }
  cout << "分别对应中奖情况如下:(特等-一等-二等-三等-四等-五等-六等)" << endl;
  cout << a << " " << b << " " << c << " " << d << " " << e << " " << f << " " << g << endl;
  }
};
void text()
{
  lottery l;
  cout << "请输入购买彩票的张数:";
  cin >> l.n;
  cout << "请输入彩票的7位中奖号码:";
  for (int i = 0; i < 7; i++)
  {
  cin >> l.arr_1[i];
  }
  cout << "请输入购买彩票的号码:" << endl;
  for (int i = 0; i < l.n; i++)
  {
  for (int j = 0; j < 7; j++)
  {
    cin >> l.arr_2[i][j];
  }
  }
  l.calculator_1();
  l.calculator_2();
}
int main()
{
  text();
}

③代码结果展示:

3.三维数组(工艺品制作)

①例题:


       现有一个长宽高分别为 w,x,h 组成的实心玻璃立方体,可以认为是由 1✖1✖1 的数个小方块组成的,每个小方块都有一个坐标( i,j,k )。现在需要进行q次切割。每次切割给出 (x1,y1,z1),(x2,y2,z2)这6个参数,保证 x1<=x2,y1<=y2,z1<=z2;每次切割时,使用激光工具切出一个立方体空洞,空洞的壁平行于立方体的面,空洞的对角点就是给出的切割参数的两个点。


       换句话说,所有满足 x1<=i<=x2 , y1<=j<=y2 , z1<=k<=z2 的小方块(i,j,k)的点都会被激光蒸发。例如有一个 4✖4✖4 的大方块,其体积为64;给出参数(1,1,1),(2,2,2)时,中间的8块小方块就会被蒸发,剩下56个小方块。现在想知道经过所有切割操作后,剩下的工艺品还剩下多少格小方块的体积。


       输入要求:分别输入长宽高三个正整数w、x、h。一个整数q,然后在接下来的q行,每行6个整数(x1,y1,z1),(x2,y2,z2)分别表示对角的两个顶点坐标;


       输出要求:输出一个整数表示切割后还剩余多少个小立方体;

  数据要求:1≤w,x,h≤20、1≤q≤100、1≤x1≤x2≤w、1≤y1≤y2≤x、1≤z1≤z2≤h;

②代码展示:

#include<iostream>
using namespace std;
#define max 21
int sq[max][max][max] = {0};
class art {
public:
  int w, x, h;
  int x1, y1, z1;
  int x2, y2, z2;
  void calculator_1()
  {
  for (int i = x1; i <= x2; i++)
    for (int j = y1; j <= y2; j++)
    for (int k = z1; k <= z2; k++)
      sq[i][j][k] = 1;
  }
  void calculator_2()
  {
  int count=0;
  for (int i = 1; i <= w; i++)
    for (int j = 1; j <= x; j++)
    for (int k = 1; k <= h; k++)
      if (sq[i][j][k] == 0)
      count++;
  cout << "剩余" << count << "个小方块" << endl;
  }
};
void text()
{
  art a;
  cout << "请输入长宽高:";
  cin >> a.w >> a.x >> a.h;
  cout << "请输入q的值:";
  int q; cin >> q;
  cout << "请分别输入两组对角点的坐标值" << endl;
  for (int num = 1; num <= q; num++)
  {
   cin >> a.x1 >>a.y1 >> a.z1;
   cin >> a.x2 >>a.y2>> a.z2;
   a.calculator_1();
  }
  a.calculator_2();
}
int main()
{
  text();
}

③代码结果展示:

总结

  以上就是我们第八章的全部讲解与典型例题,因为上面这三个例题更大程度上是数组和算法的结合应用,所以对于C++的一些初学者来说,上面的三个例题是有一定难度和挑战性的。但是如果可以独立且正确的去完成,那么你在数据结构数组这一块就可以打个对勾了。

目录
相关文章
|
2月前
|
存储 Java 程序员
数据结构之 - 深入了解数组数据结构
数据结构之 - 深入了解数组数据结构
41 6
|
3月前
|
搜索推荐 编译器 C语言
【C++核心】特殊的元素集合-数组与字符串详解
这篇文章详细讲解了C++中数组和字符串的基本概念、操作和应用,包括一维数组、二维数组的定义和使用,以及C风格字符串和C++字符串类的对比。
86 4
|
3月前
|
程序员 编译器 C++
【C++核心】C++内存分区模型分析
这篇文章详细解释了C++程序执行时内存的四个区域:代码区、全局区、栈区和堆区,以及如何在这些区域中分配和释放内存。
56 2
|
2月前
|
存储 算法 搜索推荐
探索常见数据结构:数组、链表、栈、队列、树和图
探索常见数据结构:数组、链表、栈、队列、树和图
108 64
|
20天前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
【11月更文挑战第6天】在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
33 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
2月前
|
存储 算法 搜索推荐
对二叉堆的简单分析,c和c++的简单实现
这篇文章提供了对二叉堆数据结构的简单分析,并展示了如何在C和C++中实现最小堆,包括初始化、插入元素、删除最小元素和打印堆的函数,以及一个示例程序来演示这些操作。
36 19
|
2月前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
【10月更文挑战第8天】在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。
|
2月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
23 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
2月前
|
NoSQL Redis C++
Redis的实现五:二叉堆的数据结构和TTL、c,c++的实现
这篇文章详细探讨了二叉堆的数据结构及其在C和C++中的实现,特别强调了二叉堆在Redis中实现TTL(生存时间)功能的重要性,并通过代码示例展示了如何在Redis中使用二叉堆来管理键的过期时间。
42 0