数据结构
数据:
在【向心】角度的看待下,数据可以被理解为多个不同角度的概念;例如信息的载体,其他各种各样的理解角度,在科技水平越来越发达的今日,你所触碰的一切东西可能不是数据,但它们正在朝着数据化的方向去发展。
结构:
如果螺丝和齿轮可以构造出一个颇有蒸汽朋克风格的造物,喷水壶和园丁剪刀修剪出花园,把积木拼成长方形的房子......两个元素之间如果以一种【关系】连接起来,那他们就有结构。不难理解,结构就是元素和元素之间的关系。
螺丝齿轮是元素,咬合转动就是它们之间的关系,组合在一起成为机器结构。
喷水壶、园丁剪刀、花草是元素;修剪、浇灌这种作用关系,组合成为花园系统的结构。
等等......
两个元素之间的关系是最基本二元结构,在我们现实学习中,一个结构常常是很多元素+一堆互相交织的关系。
一棵树不是只有父子两个节点,是大量节点,多层父子关系共同构成树形结构。
那么最终可以得出结论:只要元素之间存在关系,那么就构成结构;最简单的结构从两个元素的关联开始。
数据结构:
如果此时此刻存在一个班级,你作为老师,此刻的你会如何决定学生们的就坐顺序呢?
是所有人坐在前面?
还是所有人坐在后面?
后两排不让坐人?
两边最好别坐?
又如果此时此刻在你上课的时候,有一位学生迟到了,你作为老师,又会怎么做呢?
让他从前面的门进来?
让他从中间的门进来?
让他坐到后边去?
让他坐到前边去?
让他插入中间的位置?
又又如果这位同学插入到了中间的位置,其他同学还要插入这个位置吗?
又又又如果你想找到一位叫张三的同学,你会怎么做?
一下子就能找到这位同学?
还是说从头到尾挨个去问班里的每个同学,直到找到张三?
......
把同学和张三联想成数据,作为计算机系统支配者的你如何去处理这个数据,就是该考虑的问题。
以上这些就是数据结构的基本概念。
象一个班级,学生就是一条条数据。老师安排座位,就是设计数据结构: 全部坐前排、全坐后排、只留中间位置,是不同的排布方案。 有学生迟到插入座位:是插入操作 。 找学生张三:是查找操作。 插入到中间位置,是否需要挪动其他人,对应不同结构的开销差异。
用严谨的话语说明:数据结构是一种存储、组织数据的方式,旨在便于访问和修改。没有一种单一的数据结构对所有用途均有效,所以需要知道多种数据结构的优势和局限。
可!!
在数据结构的学习中,我们要学的不仅仅是数据结构。
1984年图灵奖的获得者,瑞典的计算机科学家尼可拉斯埃尼沃斯说过这么一句。
算法+数据结构=程序
算法的定义是:算法是一个有穷规则的集合,它用规则规定了解决某一特定类型问题的运算序列,或者会定了任务执行或问题求解的一系列步骤......
这么一听,或者更准确来说这么一看,算法的定义有些云里雾里,既是某一特定类型问题,又是什么任务执行问题求解。其实,用简单一句话概括就是:算法就是解决某一类问题更快捷更高效的办法。
最后,这节课到底学什么???
数据结构和算法。
更准确一点呢?
在数据结构中,我们会学习:线性表,栈,队列,数组,树与二叉树,图
在算法中,我们则是学习:查找,排序
基于C语言描述的数据结构需要哪些前置知识?
函数,数组,字符串,指针,内存解析,结构体
函数:
cpp
#include<stdio.h>
int main(int argc , char cpmst *argv[]){
int sum = 0;
for(int i = 1; i<=100; i++)
{
sum+=i;
}
printf("sum=%d\n", sum);
return 0;
}
以上是一个计算1到100的和的代码;
如果在写一个大型程序的时候,每次需要计算n个的和,都需要写这样的代码。
为了简化程序,也为了节约时间成本,通常我们会把这个代码封装成某个东西,在需要计算n个数的和时直接拿出来使用。
封装的这个东西,就是函数。
cpp
#include<stdio.h>
void fun()
{
int sum = 0;
for(int i = 1; i <= 100; i++)
{
sum += i;
}
printf("sum=%d\n", sum);
}
//调用fun函数
int main(int argc, char const *argv[])
{
fun();
return 0;
}
可以实现某个具体功能的代码块
增加代码的复用性
降低变成难度
函数不被调用是不会执行的
对内隐藏细节,对外暴露接口(面对对象的封装思想;假如说看电视机,当你按下红色按钮时,电视机会亮,你不需要知道红色按钮是出于什么样的原理操作让电视机亮的,你只需要知道按下去电视会亮;我们不知道printf的函数是怎么实现打印的,隐藏自己写的代码细节,只对外暴露出函数的名称是print,调用函数功能。)
函数参数和返回值
cpp
<返回值类型|viod> 函数名([参数列表])
{
//函数体
[return 返回值]
}
参数和返回值什么时候加,要看题目的要求:
1---没有参数,没有返回值的情况
cpp
#include<stdio.h>
/*
需求:计算1加到100的数
*/
void fun()
{
int sum = 0;
for(int i = 1; i <= 100; i++)
{
sum += i;
}
printf("sum=%d\n", sum);
}
//调用fun函数
int main(int argc, char const *argv[])
{
fun();
return 0;
}
2---没有参数,有返回值的情况
cpp
#include<stdio.h>
/*
需求:计算1加到100的数,返回计算结果。
*/
void fun()
{
int sum = 0;
for(int i = 1; i <= 100; i++)
{
sum += i;
}
return sum;
}
//调用fun函数
int main(int argc, char const *argv[])
{
//调用fun()函数来接收返回值
int s =fun();
printf("sum=%d\n", s);
return 0;
}
3---有参数,没有返回值
cpp
#include<stdio.h>
/*
需求:计算1加到n的数,并输出计算结果,n的值在调用函数时传入。
*/
void fun(int n)
{
int sum = 0;
for(int i = 1; i <= n; i++)
{
sum += i;
}
printf("sum=%d\n", s);
}
//调用fun函数
int main(int argc, char const *argv[])
{
fun(100);
return 0;
}
4---需要参数,需要返回值
cpp
#include<stdio.h>
/*
需求:计算1加到n的数,返回计算结果,n的值在调用函数时传入。
*/
void fun(int n)
{
int sum = 0;
for(int i = 1; i <= n; i++)
{
sum += i;
}
return(sum);
}
//调用fun函数
int main(int argc, char const *argv[])
{
int s = fun(100);
printf("sum=%d\n", s);
return 0;
}
字符串
字符串初始化
在c语言中,没有字符串的数据类型
通常用字符型的数组表示字符串:
char str\[\] = "HelloWorld";
|---|---|---|---|---|---|---|---|---|---|-----|
| H | e | l | l | o | W | o | r | l | d | \0 |
char str211;
str2 = "HelloWorld";
如果按照上面这种方法写字符串,则会弹出报错:
想用str211的方法写字符串,则可以通过调用strcpy
cpp
#include<stdio.h>
#include<string.h>
int main(){
char str2[11];
strcpy(str2, "HelloWorld");
}
#include<string.h>
计算机体系结构

冯诺依曼体系-计算机最基本结构

虚拟内存地址
内存条,显卡,各种适配卡都有其格子的存储空间地址
操作系统将这些设备的存储地址空间抽象成一个巨大的一维数组空间,
对于内存的每一个字节都会分配一个三十二或者六十四位的编号,这个编号称为内存地址


cpp
#include<stdio.h>
int main(int argc, char const *argv[])
{
int a = 5;
int b = 10;
printf("%p\n", &a);
printf("%p\n", &b);
return 0;
}

当获取数组地址的时候,使用取地址符&获取数组的地址时,返回的而是数组第零个元素的内存地址
cpp
#include<stdio>
int main()
{
int a[] = {1, 3, 6, 54, 66};
//输出数组的首地址(第一个元素的内存地址)、
printf("%p\n", &a);
//输出第一个元素a[0]的地址
printf("%p\n", &a[0]);
return0;
}

sizeof
cpp
#include<stdio.h>
int main(int argc, char const *argv[])
{
int a = 5;
printf("%zu\n", sizeof(a));
printf("%zu\n", sizeof(int));
printf("%zu\n", sizeof(3.14));
return 0;
}


cpp
#include<stdio.h>
int main(int argc, char const char *argv[])
{
int a[] = {16, 47, 89, 42, 38};
//数组长度不能直接写看见的数目,在循环遍历数组内元素的时候,要用sizeof来解决数组元素个数的问题,整个数组的长度除去第一个数组元素的长度:sizeof(a)/sizeof(a[0])
for(int i = 0; i < sizeof(a)/sizeof(a[0]); i++)
{
printf("%d\n", a[i]);
}
return 0;
}

指针


cpp
#include<stdio.h>
int main(int argc, char const *argv[])
{
int a = 5;
int *p = &a;
printf("a的地址为:%p,a的值为:%d\n", &a,a);
printf("p的地址为:%p,p的值为:%p\n", &p,p);
return 0;
}


当前面有声明变量(int a = 5)的时候,地址p前要加解引用符号*
·如果想打印出a里面的值,我们可以直接printf("%d\n", a),又或者,我们可以通过指针,p里面存储的是&a(a的地址),地址要用"%p\n"打印,可如果用"%d\n"的话,后面可以用解引用符号*来返回指针变量指向地址的值,简单来说,p里面的内容是是&a(0x0000000),*p里面的内容是a(5)
`假设把指针看成e的log次方,那么解引用符号*可以理解为e的ln次方,再次回到e本身值(& 和 * 就像 (ln) 和 (e^x),先后抵消。)

*p=100,按照上述的理解,p指的是&a,*p指的是a,*p赋值100,就是a赋值100
