程设期末考题解

/*
1. 计算二项式系数(15’)
给定 n, m <= 40,计算二项式系数 C(n, m) = n!/(m!(n-m)!)。保证结果在整型(int)范围内。
int binomial_coefficient(int n, int m){
//write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>
int min(int a, int b) {
int m = a < b ? a : b;
return m;
}
int binomial_coefficient_0(int n, int m) { // 按照阶乘展开公式直接计算
long double ans = 1;
for (int i = 0; i < m; i++) {
ans = ans * (n - i);
ans = ans / (m - i);
} // 乘以最大数后,立即除以最大数,缓解溢出风险
return ans; // 隐式强制转换
}
int binomial_coefficient_1(int n, int m) { // 按照二项式公式递归计算,调用函数时间开销大
if (m == 0 || n == m)
return 1; // C(n, 0) == c(n, n) == 1
return binomial_coefficient_1(n - 1, m - 1) + binomial_coefficient_1(n - 1, m);
// C(n, m) = C(n-1, m-1) + C(n-1, m)
}
int binomial_coefficient_2(int n, int m) { // 按照二项式公式递推计算,开辟数组空间开销大
int C[n + 1][m + 1];
for (int i = 0; i <= n; i++)
for (int j = 0; j <= min(i, m); j++) {
if (j == i || j == 0)
C[i][j] = 1; // C(n, 0) == c(n, n) == 1
else
C[i][j] = C[i - 1][j - 1] + C[i - 1][j]; // C(n, m) = C(n-1, m-1) + C(n-1, m)
}
return C[n][m];
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
printf("%d\n", binomial_coefficient_0(n, m));
printf("%d\n", binomial_coefficient_1(n, m));
printf("%d\n", binomial_coefficient_2(n, m));
system("pause");
return 0;
}
/*
2. 给定一个从小到大排序的链表,向链表中插入一个新的值,要求插入后的链表仍
然是有序的。(15’)
Definition for singly-linked list.
struct ListNode {
int val;
struct ListNode *next;
};
// Insert a value into the ordered linked list, returns the head of the new linked list
struct ListNode* Insert(struct ListNode* head, int new_value){
//write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>
struct ListNode {
int val;
struct ListNode* next;
};
struct ListNode* Insert(struct ListNode* head, int new_value) {
if (head == NULL) { // 如果给定的链表本身为空,则返回该新结点
struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 分配空间
new_node->val = new_value; // 赋值
new_node->next = NULL; // 初始化
return new_node; // 返回该头结点
}
else if (head->val >= new_value) { // 如果新值一开始就比头结点更小,则放到链头
struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 分配空间
new_node->val = new_value; // 赋值
new_node->next = head; // 链接到旧的头结点
return new_node; // 返回新的头结点
}
else if (head->next == NULL) { // 如果扫描到链表尾部还没找到可插入位置,就放到链尾
struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 分配空间
new_node->val = new_value; // 赋值
new_node->next = NULL; // 初始化
head->next = new_node; // 与上一个结点相连
return head; // 返回到上一级递归函数调用
}
else if ((head->next)->val >= new_value) { // 扫描到可插入位置
struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 分配空间
new_node->val = new_value; // 赋值
new_node->next = head->next; // 链接到下一结点
head->next = new_node; // 链接到上一结点
return head; // 返回到上一级递归函数调用
}
Insert(head->next, new_value); // 递归遍历整个链表
return head; // 返回头结点
}
int main() {
printf("Please enter the number of node(s): \n");
int n;
scanf("%d", &n);
struct ListNode NodeSet[n];
printf("Now please enter the value of your %d node(s) in ascending order: \n", n);
for (int i = 0; i < n - 1; i++) {
int value;
scanf("%d", &value);
NodeSet[i].val = value;
NodeSet[i].next = &NodeSet[i + 1];
}
int value;
scanf("%d", &value);
NodeSet[n - 1].val = value;
NodeSet[n - 1].next = NULL;
printf("Now please enter the new value: \n");
int new_value;
struct ListNode* head;
scanf("%d", &new_value);
head = Insert(&NodeSet[0], new_value);
printf("Now this is your new linked list: \n");
while (head) {
printf("%d ", head->val);
head = head->next;
}
putchar('\n');
system("pause");
return 0;
}
/*
3. 给定两个从小到大排序的数组,把它们合并成一个数组,保持从小到大的顺序。(20’)
int* MergeArray(int* list1, int size1, int* list2, int size2, int* return_size){
//write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>
int* MergeArray(int* list1, int size1, int* list2, int size2, int* return_size) {
*return_size = size1 + size2;
int* list_merge = (int*)malloc(sizeof(int) * (*return_size));
int ptr_merge = 0, ptr_list1 = 0, ptr_list2 = 0; // 指向每个数组的当前操作位
while (ptr_list1 < size1 && ptr_list2 < size2) { // 处理需要比较大小的部分
if (list1[ptr_list1] <= list2[ptr_list2]) { // 如果是第一个数组的元素比较小
list_merge[ptr_merge] = list1[ptr_list1];
ptr_list1++;
ptr_merge++;
}
else { // 如果是第二个数组的元素比较小
list_merge[ptr_merge] = list2[ptr_list2];
ptr_list2++;
ptr_merge++;
}
}
while (ptr_list1 < size1) { // 如果第一个数组仍有剩余部分
list_merge[ptr_merge] = list1[ptr_list1];
ptr_list1++;
ptr_merge++;
}
while (ptr_list2 < size1) { // 如果第一个数组仍有剩余部分
list_merge[ptr_merge] = list2[ptr_list2];
ptr_list2++;
ptr_merge++;
}
return list_merge; // 返回数组地址
}
int main() {
printf("Please enter the size of your first array: \n");
int size1;
scanf("%d", &size1);
int list1[size1];
printf("Now please enter your first array's %d element(s) in ascending order: \n", size1);
for (int i = 0; i < size1; i++)
scanf("%d", &list1[i]);
printf("Please enter the size of your second array: \n");
int size2;
scanf("%d", &size2);
int list2[size2];
printf("Now please enter your second array's %d element(s) in ascending order: \n", size2);
for (int i = 0; i < size2; i++)
scanf("%d", &list2[i]);
int size_merge = 0;
int* list_merge = MergeArray(list1, size1, list2, size2, &size_merge);
printf("There is your merged array with %d element(s): \n", size_merge);
for (int i = 0; i < size_merge; i++)
printf("%d ", list_merge[i]);
putchar('\n');
free(list_merge);
system("pause");
return 0;
}
/*
4. 给定一个大小为 n*n 的矩阵,计算矩阵的行列式。(20’)
double Determinant(int n , int** matrix){
//write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double SubDeterminant_0(int n, int i, int** matrix); // 余子式重整
double Determinant_0(int n, int** matrix); // 行列式按第一行展开
double Determinant_1(int n, int** matrix); // 高斯消元法
int main() {
printf("Please enter the size of your matrix: \n");
int n;
scanf("%d", &n);
int matrix[n][n];
printf("Now please enter the element(s) of your matrix: \n");
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%d", &matrix[i][j]);
printf("The determinant of your matrix is : \n%lE\n", Determinant_0(n, (int**)matrix));
printf("The determinant of your matrix is : \n%lE\n", Determinant_1(n, (int**)matrix));
system("pause");
return 0;
}
double Determinant_0(int n, int** matrix) { // 行列式按第一行展开
int(*array)[n] = (int(*)[n])matrix; // 将类型名从二重指针转换为二级数组,便于访问
if (n == 1)
return array[0][0];
else {
double sum = 0, sub_det;
for (int i = 0; i < n; i++) { // 将行列式按第一行展开
sub_det = SubDeterminant_0(n, i, matrix); // 计算每一列的余子式
sum += pow(-1, i) * sub_det * array[0][i]; // 累加代数余子式
}
return sum;
}
}
double SubDeterminant_0(int n, int i, int** matrix) {
int(*sub_matrix)[n - 1] = (int(*)[n - 1]) malloc(sizeof(int) * (n - 1) * (n - 1));
int(*array)[n] = (int(*)[n])matrix;
for (int j = 0; j < n - 1; j++) { // 重新整合余子式对应的矩阵,便于用Determinant_0()来计算
for (int m = 0; m < n - 1; m++) {
if (m < i)
sub_matrix[j][m] = array[j + 1][m];
else
sub_matrix[j][m] = array[j + 1][m + 1];
}
}
double sub_det = Determinant_0(n - 1, (int**)sub_matrix); // 继续执行下一级行列式展开
free(sub_matrix); // 释放空间
return sub_det;
}
double Determinant_1(int n, int** matrix) { // 高斯消元法
int(*array)[n] = (int(*)[n])matrix; // 将类型名从二重指针转换为二级数组,便于访问
double gauss[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
gauss[i][j] = array[i][j]; // 拷贝数据,避免对原数据修改
for (int diagonal = 0; diagonal < n; diagonal++) {
if (gauss[diagonal][diagonal] == 0) { // 如果当前对角线元素的值为 0
int row;
for (row = diagonal + 1; row < n; row++) // 则从对角线向下搜索直到找到非零数
if (gauss[row][diagonal] != 0)
break;
if (row == n) // 如果仍然搜索不到非零数
return 0; // 则该行列式为 0
for (int col = diagonal; col < n; col++)
gauss[diagonal][col] += gauss[row][col]; // 将该非零数所在的行,叠加到对角线元素所在的行,使对角线元素不为零
} // 保证对角线元素的值非零,用于之后的消元
for (int row = diagonal + 1; row < n; row++) {
double ratio = -1 * (gauss[row][diagonal] / gauss[diagonal][diagonal]); // 计算比例
for (int col = diagonal; col < n; col++)
gauss[row][col] += ratio * gauss[diagonal][col]; // 消元,将 diagonal列 中的对角线以下元素全部清零
} // 转化为上三角行列式
}
double det = 1.0;
for (int i = 0; i < n; i++)
det *= gauss[i][i]; // 上三角行列式的值等于对角线元素的乘积
return det;
}
/*
5. 给定两个字符串 a 和 b,判断 a 是否是 b 的子串。例如,当 a=”to”,
b=”cryptography”,a 是 b 的子串;当 a=”red”, b=”read”时,a 不是 b 的子串。(20’)
Given two strings a and b, decide if a is a substring of b.
bool IsSubstring(char* a, char* b){
//write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_LEN 1000
bool IsSubstring(char* a, char* b) {
int len_a = strlen(a), len_b = strlen(b);
for (int i = 0; i <= len_b - len_a; i++)
if (strncmp(a, b + i, len_a) == 0)
return true;
return false;
}
int main() {
char a[MAX_LEN], b[MAX_LEN];
printf("Please enter string a: \n");
scanf("%s", a);
printf("Now please enter string b: \n");
scanf("%s", b);
bool judge = IsSubstring(a, b);
if (judge)
printf("string a is a substring of b.\n");
else
printf("string a is NOT a substring of b.\n");
system("pause");
return 0;
}
/*
3. 给定两个从小到大排序的数组,把它们合并成一个数组,保持从小到大的顺序。(20’)
int* MergeArray(int* list1, int size1, int* list2, int size2, int* return_size){
//write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>
void Move_Hanoi(int n, char A, char B, char C) { // 原版汉诺塔
if (n == 1)
printf("%c -> %c\n", A, C);
else {
Move_Hanoi(n - 1, A, C, B); // 把上层 n-1 个圆盘从 A 移动到 B
printf("%c -> %c\n", A, C); // 把最底的第 n 个圆盘从 A 移动到 C
Move_Hanoi(n - 1, B, A, C); // 把剩余的 n-1 个圆盘从 B 移动到 C
}
}
void Hanoi(int n) {
char A = 'A', B = 'B', C = 'C';
if (n == 1)
printf("A -> B\n");
else if (n == 2)
printf("A -> B\n"
"A -> C\n");
else if (n & 2 == 1) {
Move_Hanoi(n - 1, A, B, C); // 把上层 n-1 个圆盘从 A 移动到 C
printf("A -> B\n"); // 把最底的第 n 个圆盘(n为奇数) 从 A 移动到 B
Move_Hanoi(n - 2, C, B, A); // 把剩余的 n-2 个圆盘从 C 移回到 A, 其中第 n-1 个圆盘(偶数)仍留在 C
Hanoi(n - 2); // 开始下一次判断
}
else {
Move_Hanoi(n - 1, A, C, B); // 把上层 n-1 个圆盘从 A 移动到 B
printf("A -> C\n"); // 把最底的第 n 个圆盘(n为偶数) 从 A 移动到 C
Move_Hanoi(n - 2, B, C, A); // 把剩余的 n-2 个圆盘从 B 移回到 A, 其中第 n-1 个圆盘(奇数)仍留在 B
Hanoi(n - 2); // 开始下一次判断
}
}
int main() {
printf("Please enter the size of your Hanoi: \n");
int n;
scanf("%d", &n);
printf("There is the movement of your Hanoi: \n");
Hanoi(n);
system("pause");
return 0;
}
posted @   残影0无痕  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示