数据结构能学到什么
👀数结构与算法辣么多知识😰咱们就是说这一句绘话。开始。
数据结构学啥?
1,利用程序将我们现实的问题信息化
2,利用计算机为我们高效处理问题从而能够创造价值
数据结构其他科目的作用?上图
这几门学科相互作用,形成了我们现在的信息化时代。
去
数据结构的基本概念
概念!
什么是数据?
数据是信息的载体,是描述客观事物属性的数,字符及所有能输入到计算机中并被计算机程序处理的符号集合。数据是计算机程序加工的原料。
计算机处理的形式
早期:计算机只处理纯数值型问题,如将整型或浮点型进行加减乘除
现在:主要处理非数值型问题。如处理图片,视频,音频通过二进制转换被计算机处理。
非数值型问题:
1,关心每个个体的信息
2,关心每个个体间的关系。
数据元素:描述一个个体
数据元素:
是数据的基本单位通常作为一个整体进行考虑和处理。
数据项:
是数据元素的最小单位
什么是数据对象
数据对象
:是由相同性质的数据元素的集合,是数据的一个子集。
数据结构
:是相互之间一种或多种特定关系的数据元素的集合。(强调数据元素间的关系,如)
数据结构图
字符排列与好友关系
数据对象
:是由相同性质的数据元素的集合,是数据的一个子集。所有数据项(字符)都具有名称,ASCII值,大小写)
数据结构:
是相互之间一种或多种特定关系的数据元素的集合。(强调数据元素间的关系,如字符都具有存在ASCII码表这么一种特殊的关系,但是以(隔一个字母在连线这一条件))由之前线性结构可以变为网状数据结构。如下
数据结构的三要素
我们用先用整体图来呈现.
逻辑结构
1,集合结构
每个元素都属于同一个集合无其他关系。子集都是字母由此来存放,而不是以字母顺序来存放的。
2,线性结构
数据元素之间是一对一的关系,有头有尾,A为头F为尾
3,树形结构
4,网状结构
数据元素之间是一对多的关系
数据运算
针对某种逻辑结构,结合实际需求,定义基本运算。
基本运算:
1,查找元素位置
2,添加元素位置
3,删除元素位置
存储结构
利用计算机表示元素的逻辑关系
1,顺序存储
顺序存储就是把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间地关系由存储单元的邻接关系来体现。
2,链式存储
逻辑上相邻的元素在物理位置上可以不相邻。需要元素存储地址的指针来表示元素之间的关系。
3,索引存储
在存储元素信息的同时,还要建立附加索引表。索引表中的每一项称为索引项,索引项的一般形式是(关键字,地址)
关键字可以是不一样信息,比如身份证号,地址可以是手机号码,就可以找到指定的人。数据元素在内存中是离散存放的。
4,散列存储
根据元素的关键字直接计算出该元素的存储地址,又称哈希(Hash)存储
存储结构的影响:
1,若采用顺序存储,则各个数据元素在物理位置上必须是连续的:若采用非顺序存储,则各个数据元素在物理位置上可以是离散的。
2,数据的存储结构会影响存储空间分配的方便程度。体现如下
逻辑结构是线性结构 物理结构顺序存储。将其放到内存中则需要一块连续的内存
逻辑结构是线性结构 ,物理结构是链式存储存放时,有空的地方便可以放入。
3,数据的存储结构会影响对数据运算的速度。体现如下
逻辑结构是线性结构物理结构是顺序存储 在A与C之间插入插入E则需要将C与D同时向下移动一格
逻辑结构是线性结 构物理结构是链式存储,在A与B之间插入E不需要移动剩下的三个字母。可见后者的速度更快
数据类型,抽象数据类型。
`数据类型 :是一个值的集合 和定义在此集合上 的一组操作的总称。
1,原子类型:值不可在分的数据类型
2,结构类型:值可以再分解为若干成分的数据类型
struct person类型可分解成两个int 类型
抽象数据类型
,是抽象数据组织及与之相关的操作。
逻辑结构与数据结构运算构成数据及结构 ,物理结构实现数据结构
而抽象数据研究的是逻辑,运算,存储底层原理,是如何实现的。
算法与数据结构的作用
程序=数据结构+算法
数据结构要解决的是:将现实问题信息化并存入计算机。
算法要解决的是:高效处理这些数据来解决实际问题。
什么是算法
算法是对特定问题求解步骤的一种描述。其中的每条指令表示一个或多个操作
如 物品洗发水是数据 方法1,挤洗发水。2,放到头上。3,冲水三者是算法,主要是解决洗头这一问题。
算法的特性
1,有穷性
。一个算法必须在又穷步骤之后结束,且每一条都可以在又穷时间内完成。
程序与算法是有区别的。
算法解决某个问题步骤是有穷的,如1+1如果计算步骤没有尽头不属于算法,死循环也不是。而程序是无穷的,打开王者荣耀如果我们不退出来程序会一直运行,不属于算法。
在这里插入图片描述
2,确定性
,算法中每条指令必须有确切的含义,对于相同的输入只能得到相同的输出。
输入。一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合。
输出。一个算法有一个或多个输出,这些输出是与输入有着某种特定关系的量。
举例:y=f(x);
算法步骤应该是确定性而不是存在存在 歧义性,我与老王没有规定谁前后,所以不算算法。
3,可行性
。算法中描述的操作都可以通过已经实现的基本运算执行有限次数来实现。
如果三个点不能同时满足那不是算法
“好算法的特性”
1,正确性
。算法解决,求解问题。
按年龄从大到小排序虽然我在彭于晏前面,这是一个算法,但是排列混乱。
2,可读性
。良好的可读性,帮助我们理解。如注释我们更容易去理解代码
3,健壮性
。输入非法数据时,算法能够适当做出反应或进行处理,而不是任意输出结果。本来输出的是彭于晏结果是我。
4,高效率与低存储量需求
。
高效率指时间复杂度,低存储量指空间复杂度。
时间复杂度
什么是时间复杂度
顾名思义就是做一件事需要花费的时间。如果算法在时候比较效率可能会受到与本身无关的外界因素。比如在两台新旧不一致的电脑上运算,时间可能不一样,所以计算算法的时间复杂度我们使用事前预估的方法。
事前预估算法时间的开销T(n)与问题规模n的关系,(T表示time)
我们来写一个有人敲门的程序
#include<stdio.h>
void remind(int n)
{
int i = 1; //1
for (i=1;i<=n;i++) //4
{
printf("有人能敲门\n", n); //3
}
printf("\n"); //4
};
int main()
{
int doorbell = 0;
scanf_s("%d",&doorbell);
remind(doorbell);
return 0;
}
老王上门敲了3次
分析
1执行了1次 2执行了4次(还要执行一次i++) 3执行了3次 4执行了4次
得出 T(3)=1+4+3+4 所以时间开销与问题规模n的关系:T(n)=3*n+3
如果他女友不在家他看到是老王所以不开门。老王一怒之下敲了一万次门。假如门铃有三种算法
问题规模1w足够大所以我们可以省略到三个算法低阶的部分
在描述描述时间开销时 1,只取最高阶 2, 最高阶系数化为1。
大0表示“同阶”,同等数量级。
数学思维来表示
在加法法则与乘法法则情况下我们该如何计算
我们该怎么判断哪个是低阶哪个是高阶呢?…由于考虑到数学的烧脑性( …),我们直接记住这==(常对幂指阶)==个结论。
y是时间开销T(n) x是问题规模n ,可以看出斜率k越大他的时间开销增长率越高,算法效果越差。我们用“常对幂指阶”来把这个图快速记下。
如果我们把程序的每条语句运行的次数都写出来那是不是很麻烦,我们有没有其他方法得出算法的时间复杂度呢?
第一种顺序型
#include<stdio.h>
void remind(int n)
{
int i = 1,int j=0; //1
// 一 在此顺序加入一百条语句
for (i=1;i<=n;i++) //4
{
for(j++;j<=n;j++)
{
printf("你好坏啊!\n");
}
printf("有人能敲门\n", n); //二 //3
}
printf("\n"); //4
};
int main()
{
int doorbell = 0;
scanf_s("%d",&doorbell);
remind(doorbell);
return 0;
}
程序中加入一百条顺序执行的语句,执行一百次。在原来的基础上加100,
结论一
:我们可以得出顺序执行的代码只会影响常数项,可以忽略。
当我们遇到循环的语句我们只要 管制循环里面的语句
结论二
:只要挑循环中的一个基本操作分析他的执行次数与n的关系即可。
嵌套两层循环。如果printf(“有人能敲门\n”, n);这条语句执行了n次外层的时间开销T(n)=O(n),那么printf(“你好坏啊!\n”); 执行了n^2 内层的时间开销T(n)=O(n^2)。·
结论三
:只需要考虑最深循环的循环次数与n的关系。
void INPrint(int figure[],int n)
{
int i = 1;
for (i=1;i<=100;i++ )//第一个元素开始查找。
{
if (figure[i]==88)
{
printf("找到了88这个数\n");
break;
}
}
printf("\n");
};
int main()
{
int n = 100;
int figure[] = { 0 };
printf("请输入数字:\n");
scanf_s("%d",&figure);
INPrint(figure,n);
}
最好情况:
元素n在第一个位置。 ———时间复杂度T(n)=O(1)
最坏情况:
元素n在最后一个位置 ———时间复杂度T(n)=O(n)
平均情况:
元素n在任意一个位置的概率为1/n ———时间复杂度T(n)=O(n)
空间复杂度
空间复杂度就是执行算法所需要的空间内存。研究的是空间开销与问题规模之间的关系。S(n)=n
记住一句话:研究变量内存与问题规模之间的关系
S–>space空间。
void INPrint(int n)//n为问题规模
{
int i = 1;
for (i=1;i<=n;i++)
{
printf("循环第%d次\n",i);
}
printf("\n");
};
程序开始之前代码存到内存中二进制的形式转换,大小是固定的。开始后变量i,形参n等等也占用了一定的内存空间。无论问题规模n怎么变,算法需要的内存空间都是固定的,算法空间复杂度为S(n)=O(1),我们称算法原地工作。
void INPrint(int n)//n为问题规模
{
int art[n];
int i=0;
};
这里的数组需要的空间为n*4+4+4取高阶所以S(n)=O(n)
void INPrint(int n)//n为问题规模
{
int art[n][n];
int i=0;
};
变量i与问题规模n增加的只是常数项。我们需要看的是二维数组。所占内存空间大小为4*n^2
所以S(n)=O(n^2)
void INPrint(int n)//n为问题规模
{
int art[n][n];
int or[n];
int i=0;
};
变量i与问题规模n增加的只是常数项二维数组站内存空间4n^2 一维数组站内空间4n
4*n2+4*n所以S(n)=O(n2)
** 递归调用
void INPrint(int n)//n为问题规模
{
//省略代码......
int i=0;
if(n>1)
{
INPrint(n-1);
}
printf("编程好快乐\n");
};
int main()
{
int n=3;
INPrint( n);
}
```![在这里插入图片描述](https://img-blog.csdnimg.cn/343a8a85bd72446d8a8dd2d2de98e6b8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oyH57yW56iL,size_20,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f0aee4f402be4ed89e03f1a647d9db17.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oyH57yW56iL,size_20,color_FFFFFF,t_70,g_se,x_16)
INPrint(3);函数调用参入形参3, INPrint(2);参入的形参2, INPrint(1);参入的形参1.![在这里插入图片描述](https://img-blog.csdnimg.cn/4efdc18491a346e1a1f8862bea511e7f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oyH57yW56iL,size_20,color_FFFFFF,t_70,g_se,x_16)
在这里int i增加的是常数项。所以S(n)=O(n),因此我们得出空间复杂度=递归调用的深度。
```cpp
void INPrint(int n)//n为问题规模
{
//省略代码......
int array[n];
if(n>1)
{
INPrint(n-1);
}
printf("编程好快乐\n");
};
int main()
{
int n=3;
INPrint( n);
}
函数递归中加入数组,数组元素n与每次减小的形参n一样。
得出1+2+3+…n=[n(1+n)]/2=1/2n^2+(1/2)*n等差数列。所以S(n)=O(n)
🐦咱就是说制作不易。