顺序结构、选择结构(分支结构)、循环结构
bit是位 是指为0或者1,byte是指字节,一个字节 = 八个位
十进制转换成二、八、十六进制
二、八、十六进制转换成十进制
C语言只有八、是、十六进制,没有二进制
C语言中八进制规定要义 0 开头,八进制没有8,逢8进1
C语言中十六进制规定要义 0x 开头
整型一般是 4个字节, 字符型是 1个字节,双精度一般是 8个字节
++在前 先加后用, ++在后 先用后加 自减表达式相同
格式说明 | 表示内容 | 格式说明 | 表示内容 |
---|---|---|---|
%d | 整型 int | %c | 字符 char |
%ld | 长整型 long int | %s | 字符串 |
%f | 浮点型 float | %o | 八进制 |
%lf | double | %#o | 带前导的八进制 |
%% | 输出一个百分号 | %x | 十六进制 |
%5d | %#x | 带前导的十六进制 |
printf(“%2d”,123 ); 第二部分有三位,大于指定的两位,原样输出123
printf(“%5d”,123 ); 第二部分有三位,小于指定的五位,左边补两个空格xx123 (x表空格)
printf(“%10f”,1.25 ); 小数要求补足6位的,没有六位的补0,。结果为xx1.250000 (x表空格)
printf(“%5.3f”,125 ); 小数三位,整个五位,结果为1.250(小数点算一位)
printf(“%3.1f”,1.25 );小数一位,整个三位,结果为1.3(要进行四舍五入)
eg:
scanf(“%d”,x) 错误 ; scanf(“%d”,p)正确
scanf(“%d”,&p) 错误 ; scanf(“%d”,*p)错误
C语言是用非0表示逻辑真的,用0表示逻辑假的
C语言有构造类型,没有逻辑类型
if语句没有大括号 只包括if后的第一条语句
eg: int x=5,y=1; x > y ? ‘结果为真的返回值’ : ‘结果为假的返回值’
函数:是具有一定功能的一个程序块,是C语言的基本组成单位
不能嵌套调用,但可嵌套使用
函数名缺省返回值类型,默认为int
判断质数
void isPrime(int n){
for(int i = 2;i< n;i++){
if(n % i == 0){
printf("不是质数");
break;
}else {
printf("是质数");
break;
}
}
}
int main(){
int x;
printf("输入一个正整数: ");
scanf("%d",&x);
isPrime(x);
}
求阶层
int jiecen(int n){
int result = 1;
for(int i = 1;i<=n;i++){
result *= i;
}
return result;
}
int main(){
int x;
scanf("%d", x);
printf("%d", jiecen(x));
}
参数传递
指针变量的本质是用来存放地址,而一般的变量是存放数值的
不同类型的指针变量不能赋值,不同类型的指针变量不能赋值
*p++是地址会变化。 取当前值,然后再移动地址
(*p)++ 是数值会变化。取当前值,然后再是数值增加1
例题:int *p,a[]={1,3,5,7,9};p=a;
请问*p++和(*p)++的数值分别为多少?
*p++: 这个本身的数值为1。由于是地址会增加一,所以指针指向数值3了。
(*p)++ 这个本身的数值为1。由于有个++表示数值会增加,指针不移动,但数值1由于自加了一次变成了2。
*p:一级指针:存放变量地址
**q:二级指针:存放一级指针的地址
int x=7;
int*p=&x,**q=p;
问你:*p为多少?*q为多少?**q为多少?
7 p 7
再问你:**q=&x的写法可以吗?
不可以,因为二级指针只能存放一级指针的地址。
char *s="meikanshu";
while(*s){
printf("%c",*s);
s++;
}
//这个s首先会指向第一个字母m然后通过循环会一次打印出一个字符,s++是地址移动,打印了一个字母后,就会移动到下一个字母
//传数值 传地址
void fun(int a,int b) void fun(int *a,int *b)
{ int t ; { int t ;
t=a;a=b;b=t; t=*a;*a=*b;*b=t;
} }
main() main()
{ int x=1,y=3, { int x=1,y=3,
fun(x,y); fun(&x,&y)
printf(“%d,%d”,x,y); printf(“%d,%d”,x,y);
} }
这个题目答案是1和3。 这个题目的答案就是3和1。
传数值,fun是用变量接受,所以fun中 传地址,fun用指针接受!这个时候fun
的交换不会影响到main中的x和y 。 中的交换,就会影响到main中的x和y。
传数值,形参的变化不会影响实参。 传地址形参的变化绝大多数会影响到实参!
int *fun(int *a,int *b) //可以发现函数前面有个*,这个就说明函数运算结果是地址
{ if(*a>*b)return a; //return a 可以知道返回的是a地址。
else return b;
}
main()
{ int x=7,y=8,*max;
max = fun(&x,&y); //由于fun(&x,&y)的运算结果是地址,所以用max来接收。
print("%d", max);
}
指针变量是存放地址的。并且指向哪个就等价哪个,所有出现*p的地方都可以用它等价的代替
指针变量是存放地址的。并且指向哪个就等价于哪个,所有出现*p 的地方都可以用它等价的代替
eg:
int a = 2, *p = &a;
*p = *p + 2;
//由于*p指向变量a,所以指向哪个就等价哪个,这里的*p等价于a,相当于是 a = a + 2
数组:存放的类型是一致的。多个数组元素的地址是连续的;
int a[5]={1,2,3,4,5}; 合法
int a[5]={1,2,3, }; 合法
int a[]={1,2,3,4,5}; 合法,常考,后面决定前面的大小!
int a[5]={1,2,3,4,5,6}; 不合法,赋值的个数多余数组的个数了
int a[5];注意这个地方有一个重要考点,定义时数组的个数不是变量一定是常量。
int a[5] 合法,最正常的数组
int a[1+1] 合法,个数是常量2,是个算术表达式
int a[1/2+4] 合法,同样是算术表达式
int x=5,int a[x]; 不合法,因为个数是x,是个变量,非法的,
define P 5 int a[P] 合法,define 后的的P是符号常量,只是长得像变量
int a[2][3]={1,2,3,4,5,6}; 合法,很标准的二维的赋值。
int a[2][3]={1,2,3,4,5, }; 合法,后面一个默认为0。
int a[2][3]={{1,2,3,} {4,5,6}}; 合法,每行三个。
int a[2][3]={{1,2,}{3,4,5}}; 合法,第一行最后一个默认为0。
int a[2][3]={1,2,3,4,5,6,7}; 不合法,赋值的个数多余数组的个数了。
int a[][3]={1,2,3,4,5,6}; 合法,可以缺省行的个数。
int a[2][]={1,2,3,4,5,6}; 不合法,不可以缺省列的个数。
行可省 列不可省:https://blog.csdn.net/LivingMu/article/details/111030270
一维数组的重要概念
二维数组做题技巧
如果有a[3][3]={1,2,3,4,5,6,7,8,9}这样的题目。
步骤一:把他们写成:
第一列 第二列 第三列
a[0]-> 1 2 3 ->第一行
a[1]-> 4 5 6 —>第二行
a[2]-> 7 8 9 ->第三行
步骤二:这样作题目间很简单:
*(a[0]+1)我们就知道是第一行的第一个元素往后面跳一列,那么这里就是a[0][1]元素,所以是1。
*(a[1]+2)我们就知道是第二行的第一个元素往后面跳二列。那么这里就是a[1][2]元素,所以是6。
一定记住:只要是二维数组的题目,一定是写成如上的格式,再去做题目,这样会比较简单。
数组初始化
int a[]={1,2} 合法。 int a[][4]={2,3,4}合法。 但int a[4][]={2,3,4}非法。
二维数组中的行指针
int a[1][2];
//其中a现在就是一个行指针,a+1跳一行数组元素搭配(*)p[2]指针
//a[0],a[1]现在就是一个列指针。a[0]+1 跳一个数组元素。搭配*p[2]指针数组使用
脱衣服法则
数据是操作的对象,操作的目的是对数据进行加工处理,得到期望的结果
算法 + 数据结构 = 程序
一个函数中调用另一个函数需要具备:
两中形式:
转换说明 | 输 出 |
---|---|
%a | 浮点数、十六进制数字和p-记数法 (C99) |
%A | 浮点数、十六进制数字和P-记数法 (C99) |
%c | 一个字符 |
%d | 有符号十进制整数 |
%e | 浮点数、e-记数法 |
%E | 浮点数、E-记数法 |
%f | 浮点数,十进制记数法 |
%g | 根据数值不同自动选择%f或者%e。%e格式在指数小于-4或者大于等于精度时使用 |
%G | 根据数值不同自动选择%f或者%E。%E格式在指数小于-4或者大于等于精度时使用 |
%i | 有符号十进制整数 (与%d相同) |
%o | 无符号八进制整数 |
%p | 指针(就是指地址) |
%s | 字符串 |
%u | 无符号十进制整数 |
%x | 使用十六进制数字0f 的无符号十六进制整数 |
%X | 使用十六进制数字0F的无符号十六进制整数 |
%% | 打印一个百分号 |
printf("\n*s1=%15s*", "chinabeijing");
printf("\n*s2=%-5s*", "chi");
//输出结果
*s1= chinabeijing*
*s2=chi *
n为正数(右对齐):
1.长度等于字符长度输出完整字符数组
2.长度大于字符数组长度,输出:(n - len)个空格 + 字符串数组
n为负数(左对齐):
1.长度等于字符长度输出完整字符数组
2.长度大于字符数组长度,输出:字符串数组 + (n - len)个空格
文件一般包括三要素:文件路径、文件名、后缀
C语言不仅支持对当前目录和根目录文件的操作,也支持对多级目录文件的操作
在 C 语言中 ’ \ ’ 一般是转义字符的起始标志,故在路径中需要用两个 ’ \ ’ 表示路径中目录层次的间隔,也可以使用 ‘/’ 作为路径中的分隔符
eg:D:\ \C_WorkSpace\ \Chapter_10\ \file_1.txt
D:/C_WorkSpace/Chapter_10/file_1.txt
逻辑结构
记录文件
流式文件
以字节为单位,对流式文件的访问一般采用穷举搜索的方式,效率不高
但管理简单
把抽线出来的“标准逻辑设备”或“标准文件”称作‘流’
按方向分为:输入流和输出流
按数据形式分为:文本流(ASCII码字符序列/字符序列)和二进制流(字节序列)
根据文件中数据的组织形式的不同分类
缓冲文件系统(标准文件系统)
非缓冲文件系统
ANSI C标准中只采用缓冲文件系统
调用标准库stdio.h中的fopen和fclose函数实现
FILE* fopen(char *filename, char *mode);
filename:文件名,包括路径,如果不显示含有路径,则表示当前路径
mode:文件打开模式
模式 | 含 义 | 说 明 |
---|---|---|
r | 只读 | 文件必须存在,否则打开失败 |
w | 只写 | 若文件存在,则清除原文件内容后写入;否则,新建文件后写入 |
a | 追加只写 | 若文件存在,则位置指针移到文件末尾,在文件尾部追加写人,故该方式不 删除原文件数据;若文件不存在,则打开失败 |
r+ | 读写 | 文件必须存在。在只读 r 的基础上加 ‘+’ 表示增加可写的功能。下同 |
w+ | 读写 | 新建一个文件,先向该文件中写人数据,然后可从该文件中读取数据 |
a+ | 读写 | 在” a”模式的基础上,增加可读功能 |
rb | 二进制读 | 功能同模式”r”,区别:b表示以二进制模式打开。下同 |
wb | 二进制写 | 功能同模式“w”。二进制模式 |
ab | 二进制追加 | 功能同模式”a”。二进制模式 |
rb+ | 二进制读写 | 功能同模式"r+”。二进制模式 |
wb+ | 二进制读写 | 功能同模式”w+”。二进制模式 |
ab+ | 二进制读写 | 功能同模式”a+”。二进制模式 |
优先级别最低。表达式的数值逗号最右边的那个表达式的数值
z = (2,3,4) (整个是赋值表达式) z的值为4
z = 2,3,4 (整个是逗号表达式) z的值为2
运算符 | 意义 | 示例 | 对于每个位位置的结果(1=设定,0=清除) |
---|---|---|---|
& | 位 AND | x&y | 如果 x 和 y 都为 1,则得到 1;如果 x 或 y 任何一个为 0,或都为0,则得到 0 |
| | 位 OR | x|y | 如果 x 或 y 为 1,或都为 1,则得到 1;如果 x 和 y 都为 0,则得到 0 |
^ | 位 XOR | x^y | 如果 x 或 y 的值不同,则得到 1;如果两个值相同,则得到 0 |
~ | 位 NOT(I的补码) | ~x | 如果 x 为 0,则得到 1,如果 x 是 1,则得到 0 |
运算符 | 意义 | 示例 | 结果 |
---|---|---|---|
<< | 向左移位 | x<x 的每个位向左移动 y 个位 相当与x乘以y次2 |
|
>> | 向右移位 | x>>y | x 的每个位向右移动 y 个位 相当与x除以y次2 |
strlen:是一个函数,用来计算指定字符串str的长度,但不包括结束字符(即null字符)
sizeof:是一个单目运算符,而不是一个函数.(参数可以是数组、指针、类型、对象、函数等)
数据结构的二元组形式为:DS=(D,S)
D是数据元素的集合;S是D中数据元素之间的关系集合(使用序偶来表示)
序偶是由两个元素x和y按一定顺序排列而成的二元组,记作
,x是第一个元素,y是第二个元素
全局变量全部存放在静态存储区,程序开始执行时给全局变量分配存储区,在程序结束时释放
int pointnum; // 全局变量 (最好定义与文件头)
extern int pointnum; //调用是需加关键字extern
FILE *指针名;
定义了一个指针为fp,这个指针以后只能指向文件,之后要把文件的首地址赋值给该指针
FILE *fp;
8位无符号二进制数就是从00000000到11111111
转换成10进制就是0到255
所以最大的就是255
设二维数组Arr [x] [y],初始地址Arr[0] [0]为1000,每个元素占q个字节,求Arr[n] [m]的存储地址
【折半查找二叉判定树】_CD4356的博客-CSDN博客_二叉判定树
散列地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
元素 | 11 | 22 | 47 | 92 | 16 | 3 | 7 | 29 | 8 | ||
比较次数 | 1 | 2 | 1 | 1 | 1 | 4 | 1 | 2 | 2 |
char --> short --> int —> unsigned --> long --> unsigned long --> float --> double
计算机存储、组织数据的方式,相互之间存在一种或多种特定关系的数据元素的集合
递归(recursion):递归常被用来描述以自相似方法重复事物的过程,在数学和计算机科学中,指的是在函数定义中使用函数自身的方法。(A调用A)
迭代(iteration):重复反馈过程的活动,每一次迭代的结果会作为下一次迭代的初始值。(A重复调用B)
选取序列中间结点作为根结点,分为左右部分并重复选取序列中间结点作为根结点
若左子树不为空,则左子树上各个节点的值 均小于 其根节点的值
若右子树不为空,则右子树上各个节点的值 均大于或等于 其根节点的值
左、右子树也分别具有上面两个特点
【折半查找二叉判定树】_CD4356的博客-CSDN博客_二叉判定树
v0 | v1 | v2 | v3 | v4 | v5 | v6 |
---|---|---|---|---|---|---|
0 | 2(a0) | 4(a2) | 10(v4+a6) | 7(v1+a4) | 9(a2+a8) | 14(v3+a9) |
K:图相关的最小生成树(MST) - 林学徒 - 博客园 (cnblogs.com)
直接插入排序(从首元素每次增加一位元素并排序)
12,53,1,43,65
[12,53],1,43,65
[1,12,53],43,65.....
选择排序(选择最大最小的于末首元素交换)
12,53,1,43,65
[1],53,12,43,65
[1,12],53,43,65....
冒泡排序
12,53,1,43,65
12,1,43,53,[65]
12,1,43,[53,65]....
希尔排序(根据增量分组排序,缩小增量排序)
12,53,1,43,65 gap=length/2=5/2=2
[12],{53},[1],{43},65 //按增量从首元素分组
1,43,12,53,65//第一趟排序后 gap/2
1,43,12,53,65//第二趟增量为1 则相邻的元素比较大小
1,12,43,53,65
快速排序(交换排序)
12,53,1,43,65 //首元素为基准元素
i j //j元素大于基准j--, i元素大于基准i++,其他则交换位置
12,53,1,43,65
i j //j元素交换至i
1,53,12,43,65
i j
1,12,53,43,65 //第一趟结束,第二趟取基准两边长度一半递归执行
归并排序(分治法)
12,53,1,43,65 //分至每个小组只有一个元素,then合并两个组成为新一组
[12,53],[1,43],65
[1,12,43,53],65
1,12,43,53,65
基数排序(桶排序拓展)
12,53,1,43,65 // LSD(最低为数为第一个基准) MSD(最高位数为第一个基准) 以LSD为例
//0-9个为一个桶(类似队列先进先出)
0:
1: 1
2: 12
3: 53, 43
4:
5: 65
6:
7:
8:
9:
//依次从第0桶取出元素
1,12,53,43,65 //第二趟对最低为的前一位排序
堆排序 (完全二叉树)
p = (int *)malloc(4);
p = (int *)malloc(sizeof(int));
//两个式子等价
//malloc的返回类型是void
int add(int x, int y)
{....}
main()
{ int (*f)();
f=add;
}
赋值之后:合法的调用形式为1、add(2,3);
2、f(2,3);
3、(*f)(2,3)
//传入字符串 good good study!
scanf("%s", a); //只会接收 good;不可用接受空格
gets(a); //接收good good study!;可以接收空格
#include
int main(){
char ch[] = "iamhandsome";
char *p = ch;
printf("%d \n", *p);
printf("%d \n", p);
printf("%d \n", p + 2);
printf("%d \n", *(p + 2));
printf("%d \n", *p + 2);
}
//对应ASCII码表
105 i
6422028
6422030
109 m
107 k
C语言中没有字符串变量,所以用数组和指针存放字符串:
1、char ch[10]={“abcdefgh”}; 对
2、char ch[10]=“abcdefgh”; 对
3、char ch[10]={‘a’,’b’,’c’,’d’,’e’,’f’,’g’,’h’}; 对
4、char *p=“abcdefgh”; 对
5、char *p; 对
p=“abcdefgh”;
6、char ch[10]; 错了!数组名不可以赋值!
ch=“abcdefgh”;
7、char *p={“abcdefgh”};
//把s指针中的字符串复制到t指针中的方法
1、while( (*t=*s)!=null ){s++;t++;} 完整版本
2、while( *t=*s ){s++;t++;} 简单版本
3、while( *t++=*s++); 高级版本
用来动态地分配内存空间
void* malloc (size_t size); size为需要分配的内存空间大小,以字节(Byte)计。
int *p;
p = (int *)malloc(4);
p = (int *)malloc(sizeof(int));//以上两个等价
//malloc的返回类型是 void *
static int x; //默认值为0
int x; //默认值为不定值
若用数组名作为函数调用的实参,传递给形参的是:数组的首地址
递归算法必须包括:终止条件 和 递归部分
一个链表最常用的操作是再末尾插入结点和删除尾节点,选用: 带头结点的双循环链表 最节省时间
⭐二叉树的 叶子结点 个数: n = n2 + 1;
判别有向图中是否存在回路,可使用: 拓扑排序算法
无向图的邻接矩阵是一个: 对称矩阵
循环队列存储在数组A[m]中,则入队时的操作为: rear = (rear + 1) % (m + 1);
快速排序在 被排序数据完全无序的情况下最易发挥其长处
10000个数组元素中取几个元素,采用 简单选择排序算法 最节省时间
线性表的链式存储结构,要求内存中可用存储单元的地址:连续或不连续都可以
⭐树的存储形式:
连通图:若从无向图的任意一个顶点出发进行一次深度优先搜索可以访问图中所有的
顶点
浮点型变量分别为:单精度,双精度
符号 ‘&’ 是 取地址运算符,&a是指:a在内存中的地址
在C程序中,指针变量能够赋 地址值 或 NULL(或ˊ\0ˊ,或 0,或空值)值
C语言中一个字母占一个字节。但 字符串后必须跟一个结束字符’\0’,因此总共占了2个字节
int x;
float y;
scanf("%3d%f", &x, &y);
printf("%d,%f", x,y);
//输入 12345 789
//输出 123,45.000000
C语言中,紧跟在关键字if后的一对圆括号里的表达式:可以是任意表达式
C语言中,运算对象必须是整型的运算符:%
C语言函数是由 函数头和函数体两部分组成其中,函数头包括:函数说明,函数名,圆括号中的形式参数
结构中可设定若干个不同类型的成员
结构中成员的数据类型可以是另一个已定义的结构
说明一个结构体变量(struct)时,系统分配给他的内存是:各成员所需内存量的总和
说明一个共用体变量(union)时,系统分配给他的内存是:成员中占内存里最大者所需的容量
一个共用体变量不能同时存放其所有成员
C语言共用体类型变量在程序运行期间:只有一个成员驻留在内存中
C语言中,简单变量作为实参时,它和对应形参之间的数据传递方式是:单向值传递
广义表表示法 不是树的存储形式
若采用 折半查找方法,数据文件应为 有序表,且限于顺序存储结构
串是一种特殊的线性表,体现在:数据元素是一个字符
哈夫曼树
定义:
当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,
如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,
有时也叫“赫夫曼树”或者“哈夫曼树”
相关名词:
构建原则:权重越大的结点离树根越近
AOV网是一种:有向无环图(有向无回路的图
设有n个结点的无向图
对于一个具有n个顶点和e条边的有向图和无向图,在其对应的邻接表中,所含边结点分别有e个和2e个
⭐在一个具有n个顶点的无向完全图中,包含有n(n-1)/2条边
⭐在一个具有n个顶点的有向完全图中,包含有**n(n-1)**条边
⭐无向图G中有n个顶点和e条边,则其对应的邻接表中有 n 个表头结点,2e个表结点
在图的邻接表中,每个结点被称为边结点,通常包含三个域:邻接点域、权域、链域
⭐一个连通图G中有n个顶点e条边,则其最小生成树上有 n-1 条边
某有向图有n个顶点,则该有向图对应的邻接表中有 n个表头结点
有n个顶点的强连通图,最多有n(n-1)条边,最少有n条边
设有向图G用邻接矩阵A[n] [n]作为存储结构,则该邻接矩阵中第i行上所有元素之和等于顶点i的出度,第i列上所有元素之和等于顶点i的入度
⭐设有向图G中有n个顶点e条有向边,所有顶点入度数之和为d,则 e = d
设某无向图中有n个顶点e条边
有向图的邻接表中有n个表头结点,m个表结点,则图中有 m 条有向边
在图的邻接表中,用顺序存储结构存储表头结点的优点是:可以随机访问到任意一个顶点的简单链表
设有向图G的存储结构用邻接矩阵A来表示,则A中:
设某无向图中有n个顶点e条边,则建立该图邻接表的时间复杂度是:O(n+e)
设某有向图中有n个顶点e条边,进行广度优先遍历,其算法得时间复杂度
调用一次深度优先遍历可以访问到图中的所有顶点:
⭐AOV网是一种 有向无回路的图。DAG图称为 有向无环图
设无向图G=(V,E)中含7个顶点,则图G在任何情况下都是联通的,则至少需要的边数是:
一个含有n个顶点的无向连通图采用邻接矩阵存储,则该矩阵一定是:对称矩阵
⭐设无向连通图中有n个顶点e条边若满足e≥n,则图中一定有回路
⭐对于有n个顶点的带权连通图,它的最小生成树是指图中任意一个:由n个顶点构成的极小连通子图,且边的权值之和最小
对于由n个顶点e条边的有向图,求单源最短路径的迪杰斯特拉算法(Dijkstra)的时间复杂度为O(n^2)
一个表示工程的AOE网(有向无环图)中的关键路径:可以有多条
存储稀疏图,用邻接表比使用邻接矩阵更省空间
若有向图中存在拓扑序列,则该图不存在回路
⭐完全有向图一定是强连通图,且有n个顶点的完全有向图的弧数/边数为 n(n-1)
在有n个顶点的有向图中,每个顶点的度最大可达:2(n-1)
Prim算法适合用于构造一个稠密图G的最小生成树
Kruskal算法适合构造一个稀疏图G的最小生成树
♀ 无向图的邻接矩阵,第i行上的非零元素个数和第i列的非零元素个数一定相等
设无向图的顶点个数为n,则该图最多有:n(n-1)/2条边
设无向图的顶点个数为要保证该图在任何情况下都是连通的,则需要的边数最少是: (n-1)(n-2)/2 + 1
采用邻接表存储的图的
有n个顶点的带权连通图,它的最小生成树是指图中任意一个:由n个顶点构成的极小连通图,且边的权值之和最小
对于n个顶点e条边的有向图,采用邻接矩阵表示,求单源最短路径的Dijkstra算法的时间复杂度为:O(n^2)
如果从无向图的任一顶点出发进行一次广度优先遍历即可访问所有顶点,则该图一定是:连通图
含有n个顶点的连通图中的任意一条简单路径,其长度不可能超过:n-1
如果某图的邻接矩阵是对角线元素均为零的上三角矩阵,则此图时:有向无环图
一个有向图的邻接表和逆邻接表的表结点个数一定相等
图G的拓扑序列唯一,则其弧数不一定为n-1(n为顶点个数)
n个顶点的连通图至少n-1条边,至多n(n-1)/2条边
️ 如果以图中的顶点来表示活动,有向边表示活动之间的优先关系,这种用顶点表示活动的有向图为:AOV网(有向无回路)
n个顶点的无向连通图中至少含有n-1条边
带行表的三元组表是稀疏矩阵的一种:顺序存储结构
一个图(连通图)中,生成树不唯一但最小生成树唯一(边权值之和最小)
具有n个顶点的图是一个环,则它有n-1棵生成树
DFS算法(深度优先遍历算法)的时间复杂度:O(n^2)
根据邻接矩阵求深度优先遍历的结果:
n个顶点e条边的图采用邻接矩阵存储,深度优先遍历算法的时间复杂度为 O(n^2) ;若采用邻接表存储时,该算法的时间复杂度为 O(n+e)
n个顶点e条边的图采用邻接矩阵存储,广度优先遍历算法的时间复杂度为 O(n^2) ;若采用邻接表存储,该算法的时间复杂度为 O(n+e)
图的BFS(广度)生成树的树高比DFS(深度)生成树的树高小或相等
具有n个顶点e条边的图的两种算法的最小生成树的时间复杂度:
在链表的结点中,数据元素所占的存储量和整个结点所占的存储量之比称作:存储密度
C语言标准库函数,fread(fd, buffer, n) 的功能是:
当一个共用体声明时,编译程序自动地产生一个变量,其长度为联合中最大的变量长度的整数倍。
union的存储空间先看它的成员中哪个占的空间最大,拿他与其他成员的元长度比较,如果可以整除,ok ,否则,找第一个能被整除的数
静态(static)类型变量的生存期贯穿于整个程序的运行期间
#define M(x,y,z) x*y+z
int main(int argc, char* argv[]){
int a=1,b=2,c=3;
printf("%d\n", M(a+b,b+c,c+a));
return 0;
}
/**
#define M(x,y,z) x*y+z
扩展到: a+b*b+c+c+a
**/
关系模型中的三类完整性约束:
对线性表,采用顺序存储的优点是:便于随机存取
具有n个结点的完全二叉树的第一层为根结点,若一个结点 i 满足2i>n,则该结点没有:左子结点
当调用函数时,实参是一个数组名,则向函数传递的是:数组的首地址
结构化程序设计使用顺序,选择和循环三种基本控制结构,它们的共同特点是:单入口单出口
关系数据库的规范化理论要求关系数据库中的关系必须满足起码的,即每个属性都是不可分解的
Hash算法采用开放定址法处理散列表的冲突时,其平均查找长度:高于链接法处理冲突
若需要利用形参直接访问实参时,应将形参变量说明为:引用参数
一颗结点数为n的二叉树,其所有结点的度的总和是 n-1
对于一颗具有n个结点的二叉树,用二叉链表存储时,其指针总数为2n个,其中n-1个用于指向孩子,n+1个指针是空闲(空指针域)的
对于一颗具有n个结点的二叉树从0开始进行结点的编号,并按此编号把它顺序存储到一维数组A中,即编号为0的结点存储到A[0]中,依此类推
线性表的散列存储中,处理冲突的常用方法有:开放地址法,链地址法
栈和队列的共同特点:只允许在端点处插入和删除元素
用链接方式存储的队列,在进行插入运算时:头、尾指针可能都要修改
⭐对n个记录的文件进行快速排序,所需要的辅助存储空间大致为:O(log2n)
堆排序过程中,对任一分支节点进行筛选运算的时间复杂度为O(log2n),整个堆排序过程的时间复杂度为O(nlog2n)
一种抽象数据类型包括:数据描述和操作描述两个部分
一个索引文件的索引表中,每个索引包含对应记录的索引值域和开始位置域
在对m阶的B-树插入元素的过程中,每向一个结点插入一个索引项(叶子结点的索引项为关键字和空指针)后,若该结点的索引项数等于m个,则必须把它分裂为m-1个结点
算法是指:解决问题的有限运算序列
由两个栈共享一个向量空间的好处是:节省存储空间,降低上溢发生的机率
数组data[m]作为循环队列SQ的存储空间,front为队头指针,rear为队尾指针,则执行出队操作后其头指针,front的值为:front=(front + 1)%m
一个非空广义表的表头:可以是子表或原子,表尾一定是子表
适于对动态查找表进行高效率查找的组织结构是:归并排序
不定长文件是指:记录的长度不固定
数据的逻辑结构与数据的存储(存储结构)无关,是独立于计算机的
已知一棵完全二叉树中共有N个结点,则该树中共有N/2 个叶子结点
⭐单链表上难以实现的排序方法有:快速、堆、希尔排序
多重表文件和倒排文件都归属于:多关键字文件
在多重表文件中,此关键字索引的组织方式是将次关键字相同的记录链接成一个链表
组成数据的基本单元是:数据元素
设哈夫曼树中的叶子结点总数为m,若采用二叉链表作为存储结构,则该哈夫曼树总共有 2m 个空指针域
设二叉排序树中有n个结点,则在二叉排序树的平均查找长度为:O(log2n)
设一颗完全二叉树中有500个结点,则该二叉树的深度为:500;若用二叉链表作为该完全二叉树的存储结构,则共有501个空指针域
满二叉树结点总数为:2^n - 1
1+2+4+8+16+32+64+128+245 = 500
若第九层全满, 总的节点数应为513
所以有13个节点缺失
所以 空指针域 244 x 2+6 x 2+1=501
哈夫曼树只有度为0和2的结点,没有度为1的结点
中序遍历二叉排序树中的结点可以得到一个递增的关键字序列
⭐设有n个结点的完全二叉树,如果是按照从上到下,从左到右从1开始顺序编号,则第i个结点的双亲结点编号为:i/2,右孩子的编号为:2i+1
在一颗二叉排序树中插入一个结点的时间复杂度:O(n)
二叉链表存储并不存储权值结点,只存叶子结点。(叶子结点指针域都是空的,最后一个叶子结点的右指针也是空的)
所以空指针数=叶子结点数+1
数据的最小单位:数据项
一个有序的单链表中有n个结点,要求插入一个新结点后是得单链表仍然保持有序,则该操作的时间复杂度为:O(n)
一个具有n个结点的完全二叉树的深度:
时间复杂度不受数据初始状态影响而恒为O(log2n)的是:堆排序
设二叉树的先序遍历序列和后序遍历序列,则该二叉树满足的条件是:任一结点无右孩子或任一结点无左孩子,但一定是高度等于其结点数
⭐深度为k的完全二叉树中最少有2 ^ (k - 1)个结点,最多有(2 ^ k) - 1个结点
二叉排序树上查找结点的平均时间复杂度为:O(log2n)
分块查找的平均查找长度不仅与索引表的长度有关,而且与块的长度有关
冒泡排序在初始序列逆序的情况下执行的交换次数最多
满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树
设一棵树T可以转化成二叉树BT,则二叉树BT中一定没有右子树
中序遍历二叉树可以得到一个有序的序列
设指针遍历p指向单链表中结点A,指针变量s指向被插入的新节点X,则进行插入操作的语句为(结点的指针域为next):
s->next = p->next;
p->next = s
顺序线性表中有n个数据元素,则第i个位置上插入一个数据元素需要移动表中 n + 1 - i个数据元素;删除第i个位置上的数据元素需要移动表中 n - 1个元素
二叉树的第k层的结点数最多为:2^(k-1)
向一颗B_树插入元素的过程中,若最终引起树根节点的分裂,则新树比原树的高度 增加1
⭐有效的使用HASH查找技术,必须解决的两个问题是:构造一个好的HASH函数,确定解决冲突的方法
线性表中除首尾元素之外,其他元素都仅有一个直接前驱和一个直接后继
链栈相较于顺序栈而言,优点为:通常不会出现栈满的情况
散列函数数值应按 同等概率 取其值域的每一个值
排序方法的稳定性是指:对于关键字值相同的记录,其相对位置在排序后不发生变化
稀疏矩阵的压缩存储方法一般有 三元组法和十字链表法
广义表的深度指表中所含 括号的层数
假设n个关键字均有相同的Hash函数值,若用线性探测再散列方法将这n个关键字映射存储到Hash表中,则共需 :n x (n-1)/2次探测
一颗含有n个结点的线索二叉树中,其线索个数为:n+1
⭐在一棵m阶B-树中删除一个关键字会引起合并,则该结点原有 (m/2) - 1 个关键字
设森林F对应的二叉树为B,B中有m个节点,其根结点的右子树的节点个数为n,森林F中第一棵树的节点个数是:m - n
一颗深度为k的平衡二叉树,其每个非叶子节点的平衡因子均为0,则该树共有 2^k - 1
平衡因子都为0,表示每棵左子树的深度和每棵右子树的深度均相等,即该平衡二叉树应该是满二叉树
对线性表进行折半查找时,要求线性表必须:以顺序方式存储,且节点按关键字有序排序
⭐顺序线性表中有n个数据元素,则
设指针变量p指向双向链表中结点A,指针变量s指向被插入节点x,则在结点A的后面插入结点X的操作序列为:
s->left = p;
s->right = p->right;
p->right->left = s;
p->right = s;
⭐设顺序表的长度为n,则顺序查找的平均比较次数为:(n + 1)/2
采用递归方式对顺序表进行快速排序时,递归次数与每次划分后得到的分区处理顺序无关
若某循环队列有队首指针front和队尾指针rear,在队不满时进队操作仅会改变:rear指针
对有n个记录的表进行直接插入排序,在最好情况下需要比较 n-1次关键字
对含有n个元素的关键字序列进行直接选择排序时,所需进行的关键字之间的比较次数为:n(n-1)/2
由n个无序的元素创建一个有序单链表的算法的时间复杂度是: O(nlog2n) 或 O(n^2)
顺序存储表示法(存储形式)不是m叉树(m>2)的存储形式
‼️ 关于m阶B_树:
对一个线性序列进行排序,该序列采用单链表存储,最好采用直接插入排序方法
当用一个数组data[0…n-1]存放栈中元素时,栈底最好设置在data[0]或data[n-1]处
在一颗平衡二叉树中,每个结点的平衡因子的取值范围是: -1 ~ 1
平衡因子 = 左子树深度 - 右子树深度
哈希查找中:哈希表的装填因子等于填入的记录数除以哈希表的长度
堆的形状是一颗完全二叉树,完全二叉树不一定是堆
在有n个结点的二叉链表中
满二叉树结点数一定是奇数个
顺序存储方式既能存储线性结构也能存储非线性结构
二叉树第k层最多有2^(k-1)个结点
二维数组是其数据元素为线性表的线性表
链表**不具备**可随机访问任一节点的特点
静态链表:需要分配较大空间,插入和删除不需要移动元素的线性表
在一个长度为n(n>1)的单链表上,设有头和尾两个指针,执行删除单链表中的最后一个元素操作于链表的长度有关
对线性表的操作只有两种,删除第一个元素,在最后一个元素的后面插入元素,则最好使用:只有表尾指针没有表头指针的循环单链表
顺序存储结构的优点:存储密度大
n个结点的线性表的数组实现中,访问第i(1
单链表增加一个头节点的目的是为了:方便运算的实现
队列的基本逻辑运算:
B树和B+树:
查找效率最高的二叉排序树是:平衡二叉树
直接选择排序:关键字的比较次数与记录的初始排列次序无关
❔ 堆:将所有数据序列按完全二叉树从根开始放 ,
如果所有分支都小于或者等于孩子结点关键码 ,就是小顶堆 ,反之 ,如果所有分支结点的关键码大于或者等于孩子结点关键码 ,则为大顶堆
N个结点的二叉排序树有多种,其中**树高最小的二叉排序树是最佳的**
在广义表的存储结构中,单元素节点与表元素结点有一个域对应不同,各自分别为:值域(data)和子表指针域(sublist)
**散列查找**的平均查找长度与结点个数n无关
将非零元素所在行、列、非零元素的值构成一个三元组(i,j,v) ;
对于该题:
每个非零元素占3*2=6个字节,共10个非零元素,需6*10 = 60 个字节;
此外,还一般要用三个整数来存储矩阵的行数、列数和总元素个数,又需要3*2 = 6个字节;
总共:60 + 6 = 66 个字节
在n个结点的二叉链表中,空链域为n+1个,非空链域为n-1个
在一颗m阶B树中,除根结点外,每个节点最多有m棵子树,最少有m/2棵子树
在一棵m阶B-树中删除一个关键字会引起合并,则该结点原有 (m/2)-1 个关键字
一颗结点个数为n的m(m>=3)次树中,其分支数是:n-1
一颗深度为k的平衡二叉树,其次每个非叶子结点的平衡因子均为0,则该树共有2^k - 1个结点
⭐假设有k个关键字互为同义词,若用线性探测法把这k个关键字存入哈希表中,至少要进行 k(k+1)/2 次探测
一个n x n阶的对称矩阵A,如果采用以**列优先(即以列序为主序)的压缩方式存放到一个一维数组B中,则B的容量为:n(n+1) / 2**
某算法的空间复杂度为O(1),则该算法执行所需辅组空间大小与问题规模n无关
直接插入排序在初始序列已基本有序的情况下,排序效率最高
在C语言中,二维数组元素在内存中的存放顺序是:按行存放
在C程序中,根据数据的组织形式可以分为ASCII文件和二进制文件
C语言可以利用指针实现函数返回多个值
以#号开始的语句都是预处理语句
要完全避免散列产生的堆积现象,通常采用"公共溢出区"解决冲突
n个元素的顺序表中查找元素
C语言的非空的基本数据类型包括:实型、整型、字符型
由n个键值构造的二叉排序树,在等概率查找的假设下,查找成功的平均查找长度的最大值可能达到:(n+1)/2
由两个栈共享一个向量空间的好处时:节省存储空间,减低上溢发生的机率
适于动态查找表进行高效率查找的组织结构是:三叉排序树
二叉树在线索化后,仍不能有效解决的问题是:中序线索二叉树中求中序前驱
给出不同输入序列建造二叉排序树,一定得到不同的二叉排序树
采用两类不同存储结构的字符串可分别简称为:顺序串和链串
在一个长度为n的顺序表中删除第i个元素,要移动 n-i 个元素。如果在第i个元素前插入一个元素要后移 n-i+1 个元素
在循环队列中,队头位置发生变化的操作是:出队
设主串长为n,模式串长为m(m<=n),则在匹配失败情况下,朴素匹配算法进行的无效位移次数为:n-m+1
在一棵m阶B-树中,若在某结点中插入一个新关键字而引起该结点分裂,则此结点中原有的关键字的个数是 m-1
由同一关键字集合构成的各棵二叉排序树:其形态不一定相同,平均长度也不一定相同
数据的逻辑结构在计算机存储器内的表示,称为数据的**存储结构**
产生冲突现象的两个关键字称为该散列函数的同义词
若采用孩子兄弟链表作为树的存储结构,则树的后序遍历应采用二叉树的:中序遍历算法
按排序过程中依据的原则分类,快速排序属于:交换类的排序方法
散列文件也称为直接存取文件
串匹配算法的本质是:子串定位
若需要高效的查询多关键字文件,可以采用的文件组织方式为:倒排文件
若为文件中的每个记录建立一个索引项,则建立的索引表称为:稠密索引
利用直接插入排序法的思想建立一个有序线性表的时间复杂度为:O(n^2)
设散列表中有 m 个存储单元,散列函数 H(key)= key % p ,则 p 最好选择:小于等于m的最大素数
用邻接矩阵作为图的存储结构时,则其所占用的存储空间只与图中顶点个数有关
数据结构从逻辑上划分为三种基本类型:
设二叉排序树的高度为n ,则在该树中查找关键字 key 最多需要比较n次
设一棵 m 叉树脂的结点数为 n ,用多重链表表示其存储结构,则该树中有mn-(n-1)个空指针域
具有n个结点的单链表中查找其值等于x结点是,在查找成功情况下,则平均比较 (n+1)/2 个结点
树的先根遍历序列与其对应的二叉树的先序遍历序列相同
对于两颗具有相同关键字集合而形状不同的二叉排序树,中序遍历后得到的关键字排列顺序相同
一棵高度为 5 的理想平衡树中,最少含有2 ^ (n-1)个结点,最多含有(2 ^ n)- 1个结点。
优先队列中:按优先级最高级数列先出
任何简单或复杂得算法都是由 数据结构和算法这两个要素组成
❔ 用邻接矩阵表示有n个顶点和e条边的无向图,采用压缩方式存储,矩阵中零元素的个数是:n(n+1)/2 - e
无向图中 所有顶点的度的和等于边数的2倍
数据的逻辑结构是从逻辑关系上描述数据,它与数据元素的存储结构无关
二叉树的前序遍历序列和后序遍历序列中,叶子结点之间的相对次序不变
散列方法中,表示散列表装满程度的指标a称为:装填因子
将一棵树T转换为一颗二叉树T1,在T1中结点A是结点B的父节点,则在T中,A可能是B的 父节点或兄弟结点
哈夫曼编码:
/**
* 题目:链式存储结构上建立二叉排序树
* 二叉排序树:
* 1.若左子树不空,则左子树上的所有结点小于根结点
* 2.若右子树不空,则右子树上的所有节点大于根结点
* 3.左右子树也分别为二叉排序树
* 4.没有键值相等的结点
*/
#define n 10
typedef struct node{
int key;
struct node *lchild;
struct node *rchild;
}Bitree;
void bstinsert(Bitree *bt,int key){
//为空则设置根结点的值,左右孩子为空
if(bt==0){
bt=(struct node *)malloc(sizeof(struct node));
bt->key=key;
bt->lchild=bt->rchild=0;
}
//递归子树,都比根结点小的结点
else if(bt->key>key){
bstinsert(bt->lchild,key);
}
//递归右子树,都比根结点大的结点
else{
bstinsert(bt->rchild,key);
}
}
void creatbitree(Bitree *bt){
int i;
randomize();//这里是为了保证随机生成不同的随机数
for(i=0;i<n;i++){
bstinsert(bt,random(100));
}
}
/**
* 题目:设计在链式存储结构上交换二叉树中所有结点左右子树的算法
* 递归思想
* 结点不为空就交换左右子树
*/
typedef struct node {
int key;
struct node *lchild;
struct node *rchild;
}bitree;
void swapbitree(bitree *bt){
//定义多一个变量用来保存子树
bitree *p;
if(bt == 0){
return;
}
swapbitree(bt->lchild);
swapbitree(bt->rchild);
p = bt->lchild;
bt->lchild = bt->rchild;
bt->rchild = p;
}
要求利用原单链表中结点空间设计出三个单链表的算法,使每个单链表只包含同类字符
/**
* 设单链表中有仅三类字符的数据元素 (大写字母、数字和其它字符
* 要求利用原单链表中结点空间设计出三个单链表的算法
* 使每个单链表只包含同类字符
*/
typedef struct node {
datatype data;
struct node *next;
}iklist;
void split(iklist *head, iklist *ha,iklist *hb, iklist *hc){
iklist *p;ha=0,hb=0,hc=0;
for(p = head;p!=0;p=head){
head = p->next;
p->next = 0;
if(p->data >= 'A' && p->data <= 'Z'){
p->next = ha;
ha = p;
}else if(p->data >= '0' && p->data <= '9'){
p->next = hb;
hb = p;
}else {
p->next = hc;
hc = p;
}
}
}
/**
* 判断两个二叉树是否相同
*/
typedef struct node{
datatype data;
struct node *lichild;
struct node *rchild;
}bitree;
int judebitTree(bitree *bt1, bitree *bt2){
//都为空则返回正确
if(bt1 == 0 && bt2 == 0){
return 1;
}else if(bt1 == 0 || bt2 ==0 || bt1->data != bt2->data){
return 0;
}else {
//递归二叉树
return judebitTree(bt1->lichild, bt2->lichild) *
judebitTree(bt1->rchild, bt2->rchild);
}
}
/**
* 两个有序单链表的合并排序算法
*/
typedef struct node{
int data;
struct node *next;
}Iklist;
void mergeIKList(Iklist *ha, Iklist *hb, Iklist *hc){
Iklist *s=hc=0;
while(ha != 0 && hb != 0){
if(ha->data < hb->data){
if(s == 0){
hc=s=ha;
}else {
s->next = ha;
s = ha;
}
ha = ha->next;
}
}
if(ha == 0){
s->next = hb;
}else {
s->next = ha;
}
}
/**
* 在顺序有序表中实现二分查找
*/
struct record{
int key;
int others;
};
int biSearch(struct record r[], int k){
int low=0,mid,hight=n - 1;//n=数组长度
while(low <= hight){
mid = (low+hight)/2;
if(r[mid].key == k){
return mid+1;
}else if(r[mid].key > k){
hight = mid-1;
}else {
low = mid+1;
}
}
return 0;
}
/**
* 判断二叉树是否为二叉排序树
*/
int minum = -32768,flag =1;
typedef struct node{
int key;
struct node *lchild;
struct node *rchild;
}bitree;
void inorder(bitree *bt){
if(bt != 0){
inorder(bt->lchild);
if(minum > bt->key){
flag = 0;
}
minum = bt->key;
inorder(bt->rchild);
}
}
typedef struct node{
int key;
struct node *lchild;
struct node *rchild;
}bitree;
/**
* 在链式存储结构上统计二叉树中结点个数
*/
void countNode(bitree *bt,int *count){
if(bt != 0){
count++;
countNode(bt->lchild, count);
countNode(bt->rchild, count);
}
}
//编写一个函数,给定一个数,输出大于它的且与它相邻的 5 位素数。如:输入 13,则输出 17 19 23 29 31
void prime(int num)
{
int i, j, k;
for (i = num + 1;; i++)
{ //从定义的整数向后依次加
for (j = 2; j < i; j++)
{
if (i % j == 0)
break; //如果i取余j==0,退出本轮循环
} //依次循环被除数
if (i == j)
{
printf("%d ", i); //如果i=j返回i
k++;
}
if(k>=5){
break;
}
}
}
int main()
{
int num;
scanf("%d", &num);
prime(num);
}
//编写一个函数,输入一个正整数,输出它的各个位数的平方和
void sqrtNum(int num)
{
int sum = 1; //记录平方和
int temp = 0; //记录每位数字
while (num)
{
temp = num % 10;
sum += temp * temp;
num /= 10;
}
printf("%d", sum);
}
int main()
{
int num;
scanf("%d", &num);
sqrtNum(num);
}
1.什么是数据结构?什么是数据类型
2.算法有哪些特点?算法和程序的主要区别是什么?
算法是若干指令的有穷序列,满足性质:
3.什么是指针?什么是指针变量?它们有什么关系?
4.什么是二叉树?请简述二叉树的五种基本形态
1.什么是数据结构?什么是数据类型
2.算法有哪些特点?算法和程序的主要区别是什么?
算法是若干指令的有穷序列,满足性质:
3.什么是指针?什么是指针变量?它们有什么关系?
4.什么是二叉树?请简述二叉树的五种基本形态