计算机网络+数据库+C语言的关键大题

541 阅读25分钟

1. 网络计算题

1.1 码分多址

1.1.1 码分多址习题1

两个站点A和B,要向C发送数据,采用码分多址的方法,其中:

  • A的芯片序列为: +1,-1,-1,+1,+1,+1,+1,-1
  • B的芯片序列为: -1,+1,-1,+1,-1,+1,+1,+1

请问:

  1. 如果A发送1则发出的是什么,如果A发送0则发出的是什么。
  2. AB是否可以同时发送数据?
  3. 假设A发送1,B发送1。那么C收到的码片序列是什么。
  4. 如果C接收到的码片序列(-2,+2,0,0,-2,0,0,+2)问哪个站发送数据了?发送数据的站发送的1还是0?
1. 发送1时发送芯片序列,发送0是发送芯片序列反码,则答案为:
  - 发送1时:+1,-1,-1,+1,+1,+1,+1,-1
  - 发送0时:-1,+1,+1,-1,-1,-1,-1,+1

2. 多个站点同时发送数据的时候,要求各个站点芯片序列相互正交,规格化内积为0
   (+1 -1 -1 +1 +1 +1 +1 -1)·(-1 +1 -1 +1 -1 +1 +1 +1) / 8 
   = (-1 -1 +1 +1 -1 +1 +1 -1) / 8 
   = 0
   答:可以发送数据
   
3. A发送的和B发送的在信道中被线性相加
   (+1 -1 -1 +1 +1 +1 +1 -1) + (+1 -1 +1 -1 +1 -1 -1 -1)
   = (+2 -2  0  0 +2  0  0  0)
   
4. 合并的数据和源站规格化内积
  对A内积
   (-2 +2  0  0 -2  0  0 +2)·(+1 -1 -1 +1 +1 +1 +1 -1) / 8
   =(-2 -2  0  0 -2  0  0 -2) / 8
   = -1
   可知 A 发送的为 0
   对B内积
   (-2 +2  0  0 -2  0  0 +2)·(-1 +1 -1 +1 -1 +1 +1 +1) / 8
   =(+2 +2  0  0 +2  0  0 +2) / 8
   = 1
   可知 B 发送的为 1

1.1.2 码分多址习题2

共有四个站进行码分多址 CDMA 通信。四个站的码片序列为:

  • A (-1 -1 -1 +1 +1 -1 +1 +1)
  • B (-1 -1 +1 -1 +1 +1 +1 -1)
  • C (-1 +1 -1 +1 +1 +1 -1 -1)
  • D (-1 +1 -1 -1 -1 -1 +1 -1)

现收到这样的码片序列:(-1 +1 -3 +1 -1 -3 +1 +1)。问哪个站发送数据了?发送数据的站发送的1还是0?

题解:

A站的内积:
(-1+1-3+1-1-3+1+1)·(-1-1-1+1+1-1+1+1)/8 = (+1-1+3+1-1+3+1+1)/8 = 1
B站的内积:
(-1+1-3+1-1-3+1+1)·(-1-1+1-1+1+1+1-1)/8 = (+1-1-3-1-1-3+1-1)/8 = -1
C站的内积:
(-1+1-3+1-1-3+1+1)·(-1+1-1+1+1+1-1-1)/8 = (+1+1+3+1-1-3-1-1)/8 = 0
D站的内积:
(-1+1-3+1-1-3+1+1)·(-1+1-1-1-1-1+1-1)/8 = (+1+1+3-1+1+3+1-1)/8 = 1

因此,A和D发送1B发送0,而C未发送数据。

1.1.3 码分多址习题3

一条广播信道上接有3个站点A、B、C,介质访问控制采用信道划分方法,信道的划分采用码分复用技术,A,B要向C发送数据,设A的码序列为 +1,-1,-1,+1,+1,+1,+1,-1。站B可以可以选用的码片序列为()

  1. -1,-1,-1,+1,-1,+1,+1,+1
  2. -1,+1,-1,-1,-1,+1,+1,+1
  3. -1,+1,-1,+1,-1,+1,-1,+1
  4. -1,+1,-1,+1,-1,+1,+1,+1

题解:

B站点选用的码片序列一定要与 A 站点序列正交,且规格化内积为0。分别计算ABCD:

例如D:(+1-1-1+1+1+1+1-1)·(-1+1-1+1-1+1+1+1)/8 = 0

答案为D

1.2 网络层相关

1.2.1 子网划分

注:就目前来说,现在可以使用全0和全1子网。但我们现在学习时,还强调子网划分时要去掉全0全1

现有一公司需要创建内部网络,该公司包括工程技术部,市场部,财务部,办公室4个部门,每个部门有20 - 30 台计算机,试问:

  1. 若要将几个部门从网络上分开,如果分配给该公司使用的地址为一个 C 类地址,网络地址为192.168.161.0,那么如何划分网络?可以将几个部门分开?
  2. 确定各部门的网络地址和子网掩码,并写出分配给每个部门网络中的主机IP地址范围。
答:
1. 可以采用划分子网的方法对该公司的网络进行划分。由于该公司包括4个部门,共需要划分为4个子网

2. 
已知:网络地址192.168.161.0 是一个C类地址,
	 所需的子网数为4,
	 每个子网的主机数为20-30台。
由于:自子网号和主机号不允许为全0或全1,因此子网号的比特数为3,即最多有2^3 -2 = 6 个可分配的子网,主机号的比特数为5,即每个子网最多有2^5 -2 = 30 个可分配的IP地址。
4个部门的子网掩码均为255.255.255.224,各部门的网络地址与部门主机的IP地址范围可分配如下:
————————————————————————————————————————————————————————————————————————————
|  部门    |		部门网络地址        |	  主机IP地址范围              |
| 技术部   |	192.168.161.32          | 192.168.161.33  -  192.168.161.62  |
| 市场部   |	192.168.161.64          | 192.168.161.65  -  192.168.161.94  |
| 财务部   |	192.168.161.96          | 192.168.161.97  -  192.168.161.126 |
| 办公室   |	192.168.161.128         | 192.168.161.129 -  192.168.161.158 |
————————————————————————————————————————————————————————————————————————————

1.2.2 路由聚合

在4个“/24”地址块中进行最大可能的聚合:

  1. 212.56.132.0/24
  2. 212.56.133.0/24
  3. 212.56.134.0/24
  4. 212.56.135.0/24
由于一个CIDR地址块中可以包含多个地址,所以路由表中就利用CIDR地址块来查找目的网络,这种地址的聚合常称为路由聚合。
本题已知有212.56.132.0/24、212.56.133.0/24、212.56.134.0/24、212.56.135.0/24地址块,
可知第三字节的前6位都相同,因此共同前缀8+8+6=22位,由于这4个地址块的第12个字节相同,考虑他们第3个字节即可。
	132 = 10000100
	133 = 10000101
	134 = 10000110
	135 = 10000111
所以共同的前缀有22位,所以聚合的CIDR地址块是212.56.132.0/22

1.3 检错编码

1.3.1 奇偶校验码

奇偶校验码由 1 位校验元和 n-1 位信息元构成。信息元就是发送的数据,校验元就是奇偶校验的冗余码。

  1. 奇校验:1的个数为奇数
  2. 偶校验:1的个数为偶数

如果一个字符S的ASCII编码从低到高依次为1100101,采用奇校验,在下述收到的传输后字符中,那种错误不能检测?

  1. 11000011
  2. 11001010
  3. 11001100
  4. 11010011
解析:
我们字符S的编码1100101就是n-1位信息元,如果采用奇校验,则需要在最前面添上一个冗余码,使得总共1的个数为奇数,如果采用偶校验,加上校验元后,总共1的个数则为偶数,所以这道题发送的应该是11100101

奇偶校验码特点:
只能检查出奇数个比特错误,检错能力为50%

1.3.2 CRC循环冗余码

要发送的数据是1101 0110 11,采用CRC校验,生成多项式是10011,那么最终发送的数据应该是?接收端是如何检错的?

解析: 最终发送的数据 = 要发送的数据+帧检验序列FCS(冗余码)

如何计算冗余码?

  1. 加r个0

  2. 使用模2除法

1.加0 假设生成的多项式G(x)的阶为r则加r个0

10011的多项式为x4 + x1 + x0 ,所以阶为 4 ,加4个0

则1101 0110 1100 00

2.模2除法

数据加0后使用模2除法除以多项式,余数就是冗余码

                     1100001

10011 √11010110110000

              10011  

                10011

                10011                   

                0000010110

                          10011           

                          10100

                              10011         

                                  1110

最后的1110就是冗余码(FCS)

所以最终发送的就是110101101100 1110

那么接收端是如何检错的?

把收到的在模2除法除以多项式,然后检查得到余数R。

  1. 余数为0,这个帧没有差错,接收。
  2. 余数不为0,有差错,但不知道哪错了,所以只能丢弃。

2. 数据库大题

2.1 函数依赖

2.1.1 函数依赖习题1

设有关系模式 R(职工名,项目名,工资,部门名,部门经理)

如果规定:

  • 每个职工可参加多个项目,各领一份工资;
  • 每个项目只属于一个部门管理;
  • 每个部门只有一个经理。

请回答下面几个问题:

  1. 试写出关系模式 R 的基本函数依赖和主码。
  2. 说明 R 不是 2NF 模式的理由,并把 R 分解成 2NF 。
  3. 进而将 R 分解成 3NF ,并说明理由。

分析:

--------第一问---------
1.试写出关系模式 R 的基本函数依赖和主码。

依赖关系我们使用 → 表示,可以理解为指向谁就代表可以推出谁,或者归谁管。比如:
- 职工名和项目名合在一起可以推出工资是多少就可以表示为:(职工名,项目名)→工资
- 项目归部门管,可以表示为:项目名→部门名
- 部门归部门经理管可以表示为:部门名→部门经理

好了,到现在为止我们就已经将第一问中的函数依赖写出来了,我们再来捋一下:
- 部门经理依赖于部门,也就是说要先确定部门才能确定部门经理,所以是依赖关系;
- 而部门依赖于项目,要先确定项目才能确定部门;
- 工资依赖于两个属性:职工名和项目名。

那么主码又是什么呢?
- 主码也叫主键,是指可以通过它唯一确定一条数据的这样一个属性。
- 比如学号就可以做主键,因为一个学号对应一个学生。

那么这里的主键是什么呢?
- 我们就要找通过谁可以唯一确定一条记录,
- 项目名肯定不行,因为他和职工名一起才可以确定工资,
- 那职工名肯定也不行,但是把它们合在一起就可以了,这样就可以确定唯一的一条记录。
- 所以,主键为(职工名,项目名)。

所以答案就是:
- 函数依赖关系:
  - (职工名,项目名)→工资
  - 项目名→部门名
  - 部门名→部门经理	
- 主键为(职工名,项目名)。


--------第二问---------
2.说明 R 不是 2NF 模式的理由,并把 R 分解成 2NF 。

2NF 是什么呢?
- 2NF就是一种规范,他规定不能存在部分依赖。

部分依赖是啥意思呢?
- 就是我们只看依赖于主键的属性,这里有工资和部门名,
- 但是他们两个的区别是工资对应的全部的主键,也就是两个值,
- 但是部门名只依赖于项目名,少了一个,所以是部分依赖。
- 所以他存在了部分依赖就不是 2NF 模式了。

那么怎么把它化成 2NF 呢?

- 一般我们只能通过分解的方式来消除,就是把一个关系拆成两个关系:
  - R1(项目名,部门名,部门经理)
  - R2(职工名,项目名,工资)
    这样每个关系中就不存在部分依赖了

--------第三问---------
3.进而将 R 分解成 3NF ,并说明理由。

那么 3NF 又是啥?
- 我们先来观察上面那个 2NF 的关系,
- 发现有一个关系R1(项目名,部门名,部门经理),
- 他比较特殊,就是项目名→部门名,部门名→部门经理,
- 他是连续的,就是传递性的依赖关系,3NF 就是要去掉这种依赖关系。
- 那么我们可以把 R1 再分成两个关系:
	- R11(项目名,部门名)
	- R12(部门名,部门经理)

最后总结一下 2NF 和 3NF 的关系:
|
|	1NF
|	 ↓		消除非主属性对码的部分依赖
|	2NF
|	 ↓		消除非主属性对码的传递依赖
|	3NF
↓

2.1.2 函数依赖习题2

设有关系模式R(A,B,C,D,E,F),其函数依赖集为:F={E→D,C→B,CE→F,B→A}。

请回答如下问题:

  1. 指出 R 的所有候选码并说明原因;
  2. R 最高属于第几范式,为什么?
  3. 分解 R 为 3NF。
1. 指出 R 的所有候选码并说明原因;
- 候选码就是主码,即可以作为决定性因素的属性,
- 候选码可以 → 所有的值,通俗地讲就是只能出现在箭头的前面,不能出现在后面。

- 那这里A、B、D、F四个属性肯定是不行了,只有 C和E了,
- 发现 CE 之间没有依赖关系,并且CE→ABCDEF,所以CE就是候选码。

2. R 最高属于第几范式,为什么?
- 我们来看一下有没有部分依赖,大家可以先自己想一下什么是部分依赖。

- 这里主键不是两个吗?
- 我们要找的就是哪一个属性只依赖于其中的一个主键,也就是只依赖于 C 或者 E ,
- 可以看到 B 和 D 都是部分依赖,同时 B 和 A 是传递依赖,就等同于 C→A,
- 所以 A 也是 部分依赖于 C 。那他肯定就不符合 2NF 了,那最多就是 1NF 了。

3. 分解 R 为 3NF。
- 首先分解为 2NF:模仿第一道题题目,把那个主键的单独拿出来:
	- R1(E,D) 
	- R2(C,B,A)	
	- R3(C,E,F) 
	- 区分的依据就是看看有没有依赖关系,有依赖关系就放一起。
- 然后我们化成 3NF ,就是去掉传递依赖,发现 R2 是传递依赖,
- 所以把他化成R21(C,B) 和 R22(B,A),这样就有 4 个关系了,他们都是 3NF 模式的。
	- R1(E,D) 
	- R21(C,B)
	- R22(B,A)
	- R3(C,E,F) 

2.1.3 函数依赖习题3

设有关系模式R(A,B,C,D,E),其函数依赖集为F={A→B,CE→A,E→D}

请回答如下问题:

  1. 指出 R 的所有候选码,并说明理由;
  2. R 最高属于第几范式(在1NF~3NF范围内),为什么?
  3. 将 R 分解到 3NF。
1. 候选码:CE,因为CE→ABCDE;
2. 可以看到 D 只依赖于 E,但是主键是 CE,所以 D 是部分依赖于 CE,那么最高就是 1NF 了。
3. R1={C,E,A},R2={E,D},R3={AB}

2.1.4 函数依赖习题4

设有一个记录各个球队队员每场比赛进球数的关系模式,R(队员编号,比赛场次,进球数,球队名,队长名)

如果规定,每个队员只能属于一个球队,每个球队只有一个队长。

  1. 试写出关系模式 R 的基本函数依赖和主码。
  2. 说明 R 不是 2NF 模式的理由,并把 R 分解成 2NF 。
  3. 进而将 R 分解成 3NF 。
1. 试写出关系模式 R 的基本函数依赖和主码。
- 每一个队员对应一个球队:队员编号→球队名
- 每一个球队对应一个队长:球队名→队长名
- 进球数肯定是统计的某一个场次的某一个球员的进球数,所以球员和比赛场次对应进球数:
	- (队员编号,比赛场次)→进球数
- 根据经验,主键肯定是那个两个的了。

解答:关系模式R的基本函数依赖F如下
	- F = { 队员编号→球队名,球队名→队长名,(队员编号,比赛场次)→进球数 }
	- 其主键为(队员编号,比赛场次)。

2. 说明 R 不是 2NF 模式的理由,并把 R 分解成 2NF 。
- 理由:球队名部分依赖于主键
- 分解:
	- R1={队员编号,球队名,队长名}
	- R2={球队名,比赛场次,进球数}

3. 进而将 R 分解成 3NF 。
- R11={队员编号,球队名}
- R12={球队名,队长名}
- R2={球队名,比赛场次,进球数}

2.2 关系代数

2.2.1 除运算

除法运算的一般形式示意图:

这里通过一个实例来说明除法运算的求解过程

题目: 设有关系R、S如图所示,求R÷S的结果

R:						S:
|+++++++++++|		|+++++++++++|
|  X  |  Y  |	    	|  Y  |  F  |
|+++++|+++++|           |+++++|+++++| 
|  X1 |  Y1 |           |  Y1 |  F1 |
|  X2 |  Y2 |           |  Y2 |  F3 |
|  X2 |  Y3 |           |+++++++++++|
|  X2 |  Y1 |
|+++++++++++|

解答:

1.找出关系R和关系S中相同的属性,即Y属性。
	— 在关系S中对Y做投影(即将Y列取出)
	- 所得结果如下: 
					|  Y  |
					|+++++|
					|  Y1 |
					|  Y2 |

2.找到被除关系R中与S中不相同的属性列,即X属性。
	- 关系R在属性(X)上做取消重复值的投影为{X1,X2}。
 
3.求关系R中X属性对应的像集
	- 值X1对应的像集:                   |+++++++++++|
					   |  X  |  Y  |		
					   |+++++|+++++|      
					   |  X1 |  Y1 |     
					   |+++++++++++|
	
	- 值X2对应的像集:                   |++++++++++++|
					   |  X  |  Y  |		
					   |+++++|+++++|      
					   |     |  Y1 |
                                           |  X1 |  Y2 |
                                           |     |  Y3 |
					   |+++++++++++|

4.判断包含关系
	- R÷S其实就是判断关系R中X各个值的像集是否包含关系S中属性Y的所有值。
	- 对比即可发现:
		- X1的像集只有Y1,不能包含关系S中属性Y的所有值,所以排除掉X1
		- 而X2的像集包含了关系S中的属性Y的所有值,所以R÷S的最终结果就是X2.

答案:
R÷S:
|+++++|
|  X  |
|+++++|
|  X2 |
|+++++|

除算法可以解决什么问题?

设有关系S,C,以及SC,如下所示,求SC÷C的结果

S:			   C:			   SC:
|++++++++|		|+++++++++|		|+++++++++++++++|
|  sname |		|  cname  |		| sname | cname |
|  张三  |	        |  语文  |		 | 张三  |  语文 |
|  张三  |	        |  数学  |		 | 张三  |  数学 |
|  张三  |	        |+++++++++|	         | 李四  |  数学 |
|++++++++|					|+++++++++++++++|

很容易求得结果为:{张三 }

所以你很容易看出来SC÷C 在这里解决的问题就是:“得到选修了所有课程的学生”

SC÷C的意义就是:“在S和C的联系SC中,找出与C中所有的元组有关系的R元组”。

2.2.2 差运算

差运算的一般形式示意图如下所示

【例】设有关系S,C,以及SC,如下所示,求李四不学的课程,并用关系带数表示出来

S:			   C:			   SC:
|++++++++|		|+++++++++|		 |+++++++++++++++|
|  sname |		|  cname  |		 | sname | cname |
|  张三  |	        |  语文   |		 | 张三  |  语文 |
|  张三  |	        |  数学   |		 | 张三  |  数学 |
|  张三  |	        |+++++++++|	         | 李四  |  数学 |
|++++++++|					 |+++++++++++++++|

解题思路:先求出李四学的课程,再用全部的课程 - 李四学的课程,即为李四不学的课程 。

  1. 李四学的课程。关系代数表示为:Πcnamecname=李四 (SC) )

  2. 全部的课程 - 李四学的课程:Πcname (C) - Πcnamecname=李四 (SC) )

  3. 结果:李四不学语文

2.2.3 关系代数习题

设有如图所示的三个关系,student,score,course:

  1. S
snosnameagesex
1李强23
2刘丽22
5张友22
  1. C
cnocnameteacher
k1C语言王华
k5数据库原理程军
k8编译原理程军
  1. SC
snocnograde
1k183
2k185
5k192
2k590
5k584
5k880

试用关系代数表达式表示下列查询语句:

  1. 检索至少选修成军老师所授的全部课程的学生姓名
  2. 检索李强同学不学课程的课程号
  3. 检索至少选修两门课程的同学的学号
  4. 检索全部学生都选修的课程号和课程名
  5. 检索选修课程号为K1和K5的学生学号
  6. 检索选修全部课程的学生姓名
  7. 检索选修课程包含学号为 2 的学生所选修课程的学生学号
  8. 检索选修课程名为C语言的学生学号和姓名
  9. 检索一没有一门课程成绩不及格的学生学号和姓名

答案:

  1. 检索至少选修程军老师所授的全部课程的学生姓名

解答思路: 第一步:获得选修全部程军课程的学生学号

先求出课程表中教师为程军的课程号—关系A,和所有选课表中所有的 sno,cno—关系B。

A为:Π cno  teacher=程军 (C))

B为:Π sno,cno (SC)

AB:			  
|++++++++|	   |++++++++++++++|
|  cno   |	   |  sno |  cno  |
|   k5   |	   |   1  |   k1  |
|   k8   |	   |   2  |   k1  |
|++++++++|	   |   5  |   k1  |
                   |   2  |   k5  |
                   |   5  |   k5  |
                   |   5  |   k8  |
                   |++++++++++++++|

得到关系B中所有包含关系A所有值的关系 B ÷ A,从中获得选修全部程军课程的学生学号 5

关系代数为:Π sno,cno (SC) ÷ Π cno teacher=程军 (C))

B ÷ A:
|++++++++|
|  sno   |
|   5    |
|++++++++|

第二步:从学生表中获取改学号对应的学生姓名

将 B ÷ A 与 S 做自然连接运算,得到(B÷A) ∞ S

B ÷ A:		   S:			  
|++++++++|	   |++++++++++++++++++++++++++++++++|
|  sno   |	   |  sno |  sname  |  age  |  sex  |
|   5    |	   |   1  |  李强   |   23  |   男  |
|++++++++|	   |   2  |  刘丽   |   22  |   女  |
        	   |   5  |  张友   |   22  |   男  |
		   |++++++++++++++++++++++++++++++++|

(B÷A) ∞ S :
|++++++++++++++++++++++++++++++++|
|  sno |  sname  |  age  |  sex  |
|   5  |  张友   |   22  |   男  |
|++++++++++++++++++++++++++++++++|

再将(B÷A) ∞ S 中的 sname 投影出来,Π sname ( (B÷A) ∞ S )

带入A和B的关系代数,答案的关系代数为:

​ Π sname ( (Π sno,cno (SC) ÷ Π cno teacher=程军 (C))) ∞ S )

  1. 检索李强同学不学课程的课程号

    Π cno (C) - Π cno ( σsname=李强(S) ∞ SC )

  2. 检索至少选修两门课程的同学的学号

    Π sno 1=4∧2≠5(SC × SC))

  3. 检索全部学生都选修的课程号和课程名

    Π cno,cname sno,cno(SC) ÷ Πsno(S) ∞ C)

  4. 检索选修课程号为K1和K5的学生学号

    Π sno,cno (SC) ÷ Πcno( σcno=k1∨cno=k5(C) )

  5. 检索选修全部课程的学生姓名

    Π sname ( (Π sno,cno (SC) ÷ Π cno(C)) ∞ S)

  6. 检索选修课程包含学号为 2 的学生所选修课程的学生学号

    Π sno,cno(SC) ÷ Π cnosno=2(SC))

  7. 检索选修课程名为C语言的学生学号和姓名p

    Πsno,snamesno (SC∞(σcname=C语言(C))) ∞ S)

  8. 检索一没有一门课程成绩不及格的学生学号和姓名

    Πsno,sname((Πsno(S) - Πsnograde<60(SC)) ∞ S)

2.3 SQL编程

创建数据库代码如下

--使用T-SQL语句创建名为schooldb 数据库
--数据库主文件名为schooldb_data,初始大小为10MB,最大为50mb,增长速度为5%,
--日志文件名为schooldb_1og,初始大小为10MB ,最大为100mb,增长速度为5mb,
--所有文件都放在C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER2\MSSQL\DATA 这个文件目录下

create database schooldb
on(
name = schooldb_data,
filename = 'C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER2\MSSQL\DATA\schooldb_data.mdf',
size = 10mb,
maxsize = 50mb,
filegrowth = 5)
log on
(
name = 'schooldb_1og',
filename= 'C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER2\MSSQL\DATA\schooldb_log.ldf',
size = 10mb,
maxsize = 1000mb,
filegrowth = 5mb
)
go

use schooldb
go

--根据下面三个表创建数据库
create table student
(sno char(8) primary key,
sname char(8) not null,
sex char(2) not null check(sex in ('男','女')),
sage int not null,
sdept char(8)
)
go

create table course
(cno char(8) primary key,
cname char(8) not null,
cpno char(8),
credit int,
)
go

create table sc
(sno char(8) foreign key references student(sno),
cno char(8) foreign key references course(cno),
grade int,
primary key(sno,cno)
)
go

利用上面的数据库,进行SQL编程

  1. 查询选修2门课以上(包括2门)学生学号和姓名
  2. 将‘CS’ 系全体学生的选课信息删除
  3. 创建视图 vsc(sno,sname,cno,canme,grade)。
  4. 以学生的名字创建索引ids,逆序。
  5. 删除上述建立的索引
  6. 创建存储过程proc1,通过学生姓名,可以查询此学生的全部科目的成绩。
  7. 向student表中添加约束,限定sex列的数据只能有"男"或”女“。
  8. 向student表中添加约束,使sage列的默认值为18。
  9. 给用户userdb授予查询学生表的权限。
  10. 收回用户userdb查询学生表的权限。
  11. 列出大于男生平均年龄的女生的学号,姓名,年龄,专业名,系名。
  12. 把表Student中学号为'001'的学生,现在想把其学号为‘001’修改为‘070101’。
  13. 查询平均分最高的学生学号及平均分。
-- 1. 查询选修2门课以上(包括2门)学生学号和姓名
select s.sno,s.sname
from student s, sc 
where s.sno =sc.sno
group by s.sno,s.sname
having count(s.sno) >= 2

-- 2. 将‘CS’ 系全体学生的选课信息删除
delete from sc	--这个from可以省略
from student s
where s.sno = sc.sno
and s.sdept = 'CS'

--3. 创建视图 vsc(sno,sname,cno,canme,grade)。
create view vsc(sno,sname,cno,cname,grade)
as
select s.sno, s.sname, c.cno, c.cname, sc.grade
from student s, course c, sc
where s.sno = sc.sno and c.cno = sc.cno

--4. 以学生的名字创建索引ids,逆序。
create index ids
on student(sname desc)

--5. 删除上述建立的索引
drop index student.ids

--6. 创建存储过程proc1,通过学生姓名,可以查询此学生的全部科目的成绩。
create procedure proc1
@sname char(10)
as
begin
select sname, cname, grade
from student s, course c, sc
where s.sno = sc.sno and c.cno = sc.cno
and sname = @sname
end

-- 使用方式
exec proc1 '李勇'

-- 7. 向student表中添加约束,限定sex列的数据只能有"男"或”女“。
alter table student
add constraint ch1 check(sex = '男' or sex ='女')

--不起约束名的形式
alter table student
add check(sex = '男' or sex ='女')

--8. 向student表中添加约束,使sage列的默认值为18。
alter table student
alter column sage
set default 18

--9. 给用户userdb授予查询学生表的权限。
grant select on object::student
to userdb

--10. 收回用户userdb查询学生表的权限。
revoke select on object::student
to userdb

--11. 列出大于男生平均年龄的女生的学号,姓名,年龄,系名。
select sno, sname, sage, sdept
from student 
where ssex = '女'
and sage > (select avg(sage) from student where ssex = '男')


-- 12. 把表Student中学号为'001'的学生,现在想把其学号为‘001’修改为‘070101’。
update student
set sno = '710101'
where sno = '001'

-- 13. 查询平均分最高的学生学号及平均分。
select top 1 sno, avg(grade) as avgGrade
from sc
group by sno
order by avg(grade) desc

3.C语言编程题

3.1 平年闰年问题

输入某天的年月日,计算该天为当年的第几天

输入:

1998,9,25

输出:

9月25日是1998年的第268天
  • 能被4整除却不能被100整除,或能被400整除的年份是闰年。

  • 闰年的2月为29天,平年的2月为28天

代码:

/**
 * 输入某天的年月日,计算该天为当年的第几天
 * 输入:
 * 1998,9,25
 * 输出:
 * 9月25日是1998年的第268天
 * 闰年的额判断方法为:
 * 能被4整除却不能被100整除,或能被400整除的年份是闰年。
 * 闰年的2月为29天,平年的2月为28天
*/

#include <stdio.h>

int main() {
    int year,month,day;
    scanf("%d,%d,%d",&year, &month, &day);

    int arr[12] = {31,-999,31,30,31,30,31,31,30,31,30,31}; //2月待定
    //判断是否为闰年
    if ((year%4 == 0 && year%100 != 0) || year%400 == 0) {
        arr[1] = 29;
    } else {
        arr[1] = 28;
    }

    int answer = 0;
    int i;
    //如果求的是9月x号那么需要先累加1-8月每月固定的天数,
    //在数组里,则是索引为0-7的元素,也就是0累加到month-2。
    for (i = 0; i <= month - 2; i++) {
        answer += arr[i];
    }

    answer += day;

    printf("%d月%d日是%d年的第%d天\n",month,day,year,answer);
    return 0;
}

3.2 自守数问题

自守数是指一个数的平方的尾数等于该数自身的自然数

例如:5^2 = 25, 25^2 = 625, 76^2 = 5776,9376^2 = 87909376

题目:编写一个程序输出10000以内的自守数。

/**
 * 自守数是指一个数的平方的尾数等于该数自身的自然数
 * 例如:5^2 = 25, 25^2 = 625, 
 *      76^2 = 5776,9376^2 = 87909376
 * 编写一个程序输出10000以内的自守数
*/

#include <stdio.h>

int getDigit(int num) {
    int i;
    for (i = 1; i <= 6; i++) {
        num = num / 10;
        if (num < 1) {
            break;
        }
    }
    return i;
}

int getTen(int d) {
    int i = 1;
    int ten = 10;
    while (i < d) {
        ten = ten * 10;
        i++;
    }
    return ten;
}


int main() {
    int d;          //自守数位数,比如9376^2 = 8790937 则i=4
    int num;        //原数
    int sqNum;      //平方后的数
    int sqNumLast;  //平方数的后d位数
    for (num = 0; num <= 10000; num++) {
        d = getDigit(num);		
        sqNum = num * num;
        sqNumLast = sqNum % getTen(d);	//如后有d位,则需余10^d。
        if (num == sqNumLast) {      
            printf("%d ",num); 
        }
    }
    return 0;
}
0 1 5 6 25 76 376 625 9376
--------------------------------
Process exited after 0.0452 seconds with return value 0
请按任意键继续. . .

3.4 结构体编程题

有5个学生,每个学生有3门课成绩,要求实现如下3个功能,请给出程序的实现代码。

  1. 从键盘输入5个学生的数据,包括学号,姓名,3门课成绩
  2. 计算每门课的平均成绩和每个学生的平均成绩。
  3. 按每个学生的平均成绩由小到大进行排序。排序后按顺序输出学生姓名。
/*
有5个学生,每个学生有3门课成绩,要求实现如下3个功能,请给出程序的实现代码。
1. 从键盘输入5个学生的数据,包括学号,姓名,3门课成绩
2. 计算每门课的平均成绩和每个学生的平均成绩。
3. 按每个学生的平均成绩由小到大进行排序。排序后按顺序输出学生学号和姓名和平均成绩。
*/

#include <stdio.h>

typedef struct {
    int sno;
    char sname[20];
    double grade[3];    
} Student;

void avgCourse(Student stu[5], double avgCourseGrade[3]);       //计算每个门课的平均成绩
void avgStudent(Student stu[5], double asg[5]);                 //计算每个学生的平均成绩
void sortStudentAsAvgGrade(Student stu[5], double asg[5]);      //使每个学生按平均成绩从小到大排序
void swapStudent(Student *one, Student *two);                   //交换两个学生的全部信息,用于排序
void swapAvgGradeArr(double *one, double *two);                 //交换平均成绩数组中的两个值,用于排序

/**
 * 描述:主函数 
 * 
 * @acg: 每门课程的平均成绩数组
 * @asg:每个学生的平均成绩数组
 * @stu:用来表示5个学生的数组
 */
int main() {
    Student stu[5];
    double acg[3];
    double asg[5];
    int i, j, k;
    
    //功能1
    for (i = 0; i < 5; i++) {
        printf("请输入第%d为同学的信息:\n", i+1);
        printf("学号:");
        scanf("%d", &stu[i].sno);
        printf("姓名:");
        scanf("%s", stu[i].sname);
        printf("成绩一:");
        scanf("%lf", &stu[i].grade[0]);
        printf("成绩二:");
        scanf("%lf", &stu[i].grade[1]);
        printf("成绩三:");
        scanf("%lf", &stu[i].grade[2]);
    }

    //功能2
    printf("\n每门课的平均成绩:\n");
    //通过函数,使acg数组获取到每门课的平均成绩
    avgCourse(stu, acg);  
    //循环输出
    for (i = 0; i < 3; i++) {
        printf("第%d门课的平均成绩为:%f\n",i, acg[i]);
    }

    printf("\n每位学生的平均成绩:\n");
    //通过函数,使asg数组获取到每个学生的的平均成绩
    avgStudent(stu, asg);
    //循环输出
    for (i = 0; i < 5; i++) {
        printf("%s的平均成绩为:%f\n",stu[i].sname, asg[i]);
    }

    //功能3
    printf("\n排序后按顺序输出学生学号和姓名和平均成绩。\n");
    sortStudentAsAvgGrade(stu, asg);
    for(i = 0; i < 5; i++) {
        printf("%d %s %f \n", stu[i].sno, stu[i].sname, asg[i]);
    }
}

/**
 * 描述 : 计算每个门课的平均成绩
 * 接收主函数的两个数组,一个stu,一个acg
 * 三门课的成绩保存在 acg中
 * 由于C语言的语法,函数参数为数组时为地址传递
 * 可以改变数组中原先的值。
 * 
 * 函数中有两个循环
 * 最外层的for i 一共3次,每次算出一门课的平均成绩
 * 内层的for j 一共5次,每次累加1位学生的第i门课的成绩,
 * for j 的5次循环则可以累加出5位学生的第i门课的成绩
 */ 
void avgCourse(Student stu[5], double acg[3]) {
    int i, j;
    double sum;
    for (i = 0; i < 3; i++) {
        sum = 0;
        for (j = 0; j < 5; j++) {
            sum += stu[j].grade[i];
        }
        acg[i] = sum / 5;
    }
}

/**
 * 描述 : 计算每个学生的平均成绩
 * 
 * for i 一共5次,每次循环计算1位学生的平均分
 * 首先sum累加第i位同学的总成绩,再除以3。
 * 得到的平均分保存在数组 asg 中
 * C语言函数参数为数组时进行地址传递,所以也改变主函数中asg数组的值。
 */
void avgStudent(Student stu[5], double asg[5] ) {
    int i;
    double sum;
    for (i = 0; i < 5; i++) {
        sum = 0;
        sum += stu[i].grade[0];
        sum += stu[i].grade[1];
        sum += stu[i].grade[2];
        asg[i] = sum / 3;
    }
}

/**
 * 描述 : 使每个学生按平均成绩从小到大排序
 * 
 * 首先,stu的5个学生和asg的5个平均成绩是一一对应的。
 * 也就是说,stu[1]这位同学的平均成绩是asg[1],sty[2]的平均成绩是asg[2]
 * 
 * 所以,我们只需要对asg数组进行从小到大排序,
 * 排序时,asg数组中的每个元素发生交换的同事,stu数组的也跟着发生交换。
 * 具体的排序算法使用的是冒泡排序,排序方案另学
 */
void sortStudentAsAvgGrade(Student stu[5], double asg[5]){
    int i, j;
    for (i = 0; i < 5; i++) {
        for (j = 0; j < 4; j++) {
            if (asg[j] > asg[j+1]) {
                swapAvgGradeArr(&asg[j], &asg[j+1]);
                swapStudent(&stu[j], &stu[j+1]);
            }
        }
    }
}

/**
 * 描述 :用于排序中的交换两个浮点数
 *  
 * 由于要改变原值,所以必须要地址传递,则需要用指针来接收参数
 */
void swapAvgGradeArr(double *one, double *two) {
    double temp = *one;
    *one = *two;
    *two = temp;
}

/**
 * 描述 :用于排序中的交换两个stu
 */
void swapStudent(Student *one, Student *two) {
    Student temp = *one;
    *one = *two;
    *two = temp;
}

程序运行结构

请输入第1为同学的信息:
学号:1001
姓名:白大
成绩一:100
成绩二:91
成绩三:98
请输入第2为同学的信息:
学号:1002
姓名:刘二
成绩一:90
成绩二:91
成绩三:92
请输入第3为同学的信息:
学号:1003
姓名:张三
成绩一:80
成绩二:85
成绩三:88
请输入第4为同学的信息:
学号:1004
姓名:李四
成绩一:70
成绩二:77
成绩三:78
请输入第5为同学的信息:
学号:1005
姓名:王五
成绩一:60
成绩二:66
成绩三:61

每门课的平均成绩:
第0门课的平均成绩为:80.000000
第1门课的平均成绩为:82.000000
第2门课的平均成绩为:83.400000

每位学生的平均成绩:
白大的平均成绩为:96.333333
刘二的平均成绩为:91.000000
张三的平均成绩为:84.333333
李四的平均成绩为:75.000000
王五的平均成绩为:62.333333

排序后按顺序输出学生学号和姓名和平均成绩。
1005 王五 62.333333
1004 李四 75.000000
1003 张三 84.333333
1002 刘二 91.000000
1001 白大 96.333333

--------------------------------
Process exited after 87.18 seconds with return value 21
请按任意键继续. . .