数据结构--数据抽象
C
语言除了内置类型还提供了两种聚合数据类型:数组,结构题;- 首先解释一下数据类型:数据类型是数据对象和施加在数据对象上面操作的聚合体;
* 1.首先包含两个部分:数据对象和数据对象的操作,这个类似于`C++`的类,类里面就是用来定义数据对象和数据对象的操作,可以说类是数聚类型的一个实现;
- 抽象数据类型中的数据对象和数据操作的规范声明与数据对象的表示和操作的实现相互分离;
- 对于抽象数据类型中的功能实现,也就是函数通常需要包括一下类别:
* 1.创建函数/构造函数:用来创建新的实例,例如`C++`语言中的:默认构造函数,拷贝构造函数等;
* 2.变换函数:可以用于为特定创建特定实例;
* 3.报告函数/观察函数,这些函数提供实例信息但是不会进行修改;
- 对于程序的分析:
* 1.程序是否符合任务的规范说明;
* 2.程序是否有正确的输出;
* 3.程序是否能够根据逻辑分解成为有效执行的函数;
* 4.程序是否能够处理异常等情况;
* 5.程序是使用内存和外存是否合理;
* 6.程序的运行时间是否合理;
- 程序的空间复杂度:程序运行时,所需要的空间;
* 1.定长空间需求,包括:指令空间,简单变量的存储空间,定长结构变量的存储空间,常量存储空间;
* 2.变长空间需求:结构化变量所需要的空间,例如递归程序运行时,额外开辟的空间;
- 时间复杂度:程序运行的时间;
* 1.程序的时间复杂度;
* 2.程序步:程序步是与实例特征无关的,根据语法或者语义划分的程序片段;
* 对于每一个分号就是一个程序步,但是循环里面的是需要按照循环进行计算的;
- 通过程序步的概念来计算和统计程序的时间复杂度在绝大多数情况下都是不可行的,通常情况下是使用渐进记号来统计时间复杂度的;
- 对于程序的运行时间建议使用时间计数来进行统计;
方法1 | 方法2 | |
---|---|---|
启动定时时钟 | start=clock() | start=time(NULL) |
停止计时时钟 | stop=clock() | stop=time(NULL) |
返回值类型 | clock_t | time_t |
返回时间 | duration=((double)(stop-start)) | difftime(stop,start) |
- 看一个有意思的题吧,关于奇数阶魔方的处理方法:
- 魔方其实是
n*n
阶的矩阵,范围从1-n^2
,要求是每行每列,以及主对角线的和必须相等; - 首先来看看
Coxeter
提出的问题的解决方法:
* 1.因为是偶数阶魔方,所以找到第一行的中间放1
,然后向坐上移动一格,把当前数加1
放置在这个位置;
* 2.如果一行超出范围,可以从上边界直接到下边界,从左边界到右边界;
* 3.如果这个位置左上方已经有数字,那么就往这个位置的正下方添加数字;
* 4.一直到所有的数字都填满为止;
例如这张图: - 在填充数据的过程中,一共有这几种情况需要考虑:
- 1.首先将
1
填充在第一行的中间位置,在填充2
时,由于已经跨越上边界,所以需要自动转到下边界,所以2
的位置就在第三行的最后一列; - 2.在填充
3
的过程中,遭遇到了左边界,所以自动跨越,到右边界,4
的位置就可以确定; - 3.
5
的位置在4
的左上方是符合要求的,5
的左上方已经有1
存在所以直接在5
的正下方填写6
,这个过程都是符合要求的; 接下来尝试使用程序来实现这个过程:
include
using namespace std;
void fill_mufang(int array[][5],size_t n){
//异常处理if(n<1||!(n%2))
exit;
int row=0;
int col=0;
int i=0;
int j=n/2;
size_t fill_number=1;
//首先赋值第一个元素,第一行的中间元素;
array[0][n/2]=fill_number++;
for(;fill_number<=n*n;fill_number++){
//改变row,col,用来判断下一个移动的元素是否需要改变;
row = (i-1<0)? n-1:i-1;
col = (j-1<0)? n-1:j-1;
//如果元素已经有值,那么就改变i的值;
if(array[row][col]) i=++i%n;
else{i=row;j=(j-1<0)?(n-1):--j;}
//移动i,j进行元素赋值操作;
array[i][j]=fill_number;
}
for(size_t i=0;i<n;++i){
for(size_t j=0;j<n;++j){
printf("%d\t",array[i][j]);
}
printf("\n");
}
}
int main(){
int array[5][5]={
{
0}};fill_mufang(array,5);
}
程序的执行结果是
- 解释一下这里面的关键的几个执行语句:
* 1.`row=(j-1)<0?(n-1):j-1`,这句话其实是一个简单的判断语句表示的含义是:如果`j-1<0`,那么`row`的值就是`(n-1)`,否则就是`j-1`,因为使用`row`表示的是行数,行数向上移动,列数向左移动,本质都是减一操作,但是当行数变为负数时,就应该变为行数的最大行,所以只需要使用`n-1`就可以;
* 2.对于列数的变换也是同样的道理;
* 3.`if(array[i][j])`首先数组进行了初始化操作,元素为0,如果这条语句为真表示的含义是`array[i][j]`的值不是`0`,也就是在进行左上移动的操作后这里的元素已经有值;那么`j`不发生改变,`i`应该进行加操作,为了防止超出范围使用`%`操作;
* 4.`i=row;j=(j-1<0)?(n-1):j-1;`,因为使用的是`i`和`j`来移动并且改变元素的,`row`和`col`只是用来判断下一个元素是否需要改变的;
* 5.最后进行赋值操作;
- 偶数阶幻方按照填充的过程进行处理,这里有一点小问题,在二位数组传参应该考虑使用引用的方式传参;
还没有评论,来说两句吧...