目录
7-3 递归法求Hanoi塔输出
题目:
题目描述:递归方法进行Hanoi塔问题求解,这里要求输入Hanoi塔层数n,输出盘子移动步骤。
汉诺塔问题:有三根杆子X,Y,Z。X杆上有n个(1<=n<=10)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至Z杆:每次只能移动一个圆盘,大盘不能叠在小盘上面。求解步骤可参照下图:
输入格式:
输入为一个正整数n为盘子数目,且1<=n<=10。
输出格式:
输出每一步移动盘子的记录。一次移动一行。
每次移动的记录为例如3:X->Y 的形式,即把编号为3的盘子从X杆移至Y杆。
我们约定圆盘从小到大编号为1, 2, ...n。即最上面那个最小的圆盘编号为1,最下面最大的圆盘编号为n。
输入样例:
在这里给出一组输入。例如:
3
输出样例:
在这里给出相应的输出。例如:
1:X->Z
2:X->Y
1:Z->Y
3:X->Z
1:Y->X
2:Y->Z
1:X->Z
输入样例:
在这里给出一组输入。例如:
0
输出样例:
在这里给出相应的输出。例如:
Wrong Input.
思路:
一个非常经典的递归问题,关键要找到程序的出口和递归关系。
ps:为作区分,将盘数记为num,每个盘编号为1~n
1.当num=1,可以直接从X移到Z
2.num!=1时,将前n-1个看做一个整体,记为(n-1):
将(n-1)从X借Z移到Y,(X--(Z)-->Y)
那么此时,只有1个盘(编号为n),则为情况1(num=1)
现在,(n-1)在Y位置,只需要将(n-1)从Y借X移到Z(Y--(X)-->Z)
#include<stdio.h>
void hanoi(int n,char a,char b,char c){
if(n==1){
printf("%d:%c->%c\n",n,a,c);//情况1,直接从X->Z
}else if(n>=1&&n<=10){
hanoi(n-1,a,c,b); //(n-1)从X借Z到Y,此时(n-1)在Y上
printf("%d:%c->%c\n",n,a,c);
hanoi(n-1,b,a,c); //(n-1)从Y借X到Z
}
}
int main() {
int n;
scanf("%d", &n);
if (n < 1 || n > 10) {
printf("Wrong Input.\n");
return 0;
}
hanoi(n, 'X', 'Y', 'Z');
return 0;
}
7-7 头插法创建单链表、遍历链表、删除链表
题目:
输入一系列自然数(0和正整数),输入-1时表示输入结束。按照输入的顺序,用头插法建立单链表,并遍历所建立的单链表,输出这些数据。注意 -1 不加入链表。
输入格式:
第一行是一个正整数k,表示以下会有k组测试数据。
每组测试数据是一系列以空格隔开的自然数(0和正整数)。数列末尾的 -1 表示本组测试数据结束。按照输入的顺序,用头插法建立单链表,并遍历所建立的单链表,输出这些数据。注意 -1 不加入链表。
输出格式:
对于每组测试数据,输出链表中各节点的数据域。每个数据后有一个空格。每组测试数据的输出占1行。
输入样例:
3
1 2 3 4 5 -1
30 20 10 -1
4 2 2 1 1 2 0 2 -1
输出样例:
在这里给出相应的输出。例如:
5 4 3 2 1
10 20 30
2 0 2 1 1 2 2 4
注意:对每组测试数据,创建链表,遍历链表输出之后,一定要删除链表,否则会出现“内存超限”。
思路:
链表的基本操作,需要注意:
1.头插法和尾插的区别,使用头插法时,链表遍历的顺序为输入顺序的逆序
eg:
输入: 10 -9 2 8 6
存储顺序:( ^ 表示在此插入数据)
a.^
b.^ 10
c.^ -9 10
d.^ 2 -9 10
e.^ 8 2 -9 10
f. 6 8 2 -9 10
2.malloc和free 配合使用,free释放空间
#include <stdio.h>
#include <stdlib.h>
struct Node {
int num;
struct Node* next;
};
struct Node* createLinkedList() {
struct Node* head = NULL;
int value;
while (1) {
scanf("%d", &value);
if (value == -1) {
break;
}
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->num = value;
newNode->next = head; //插在头部
head = newNode; //改变头指针
}
return head;
}
// 遍历链表
void traverseAndPrint(struct Node* head) {
struct Node* p = head;
while (p != NULL) {
printf("%d ", p->num);
p = p->next;
}
printf("\n");
}
// 删除链表释放内存
void deleteLinkedList(struct Node* head) {
struct Node* p = head;
while (p != NULL) {
struct Node* temp = p;
p = p->next;
free(temp);
}
}
int main() {
int k;
scanf("%d", &k);
for (int i = 0; i < k; i++) {
struct Node* head = createLinkedList();
traverseAndPrint(head);
deleteLinkedList(head);
}
return 0;
}
知识点:链表的插入与删除
插入:![](https://i-blog.csdnimg.cn/blog_migrate/59077f15302aeee04e67319658d17aff.png)
删除:![](https://i-blog.csdnimg.cn/blog_migrate/1f188c2289ccdebeb48444e039c548b2.png)
7-8 单链表基础应用(1)--创建链表
题目:
编程实现一个简易学生信息管理系统,按如下步骤分别用自定义函数实现:
(1) 根据输入信息创建单链表。每个学生的信息包括姓名和成绩;
(2) 输出简易学生信息管理系统(单链表)的所有学生(结点)信息。
输入格式:
根据输入的若干个学生信息创建单链表。每一行代表一个学生信息,以成绩-1作为输入的结束。
输出格式:
每个学生信息占一行,姓名和成绩之间以空格分隔,成绩保留一位小数。
输入样例:
在这里给出一组输入。例如:
Cai 61.2
Cai 64.6
Cheng 68.4
Xiao 71.2
Zhang 83.2
Liu 90.4
Xiao 92.6
Cai 96.8
xx -1
输出样例:
在这里给出相应的输出。例如:
Cai 61.2
Cai 64.6
Cheng 68.4
Xiao 71.2
Zhang 83.2
Liu 90.4
Xiao 92.6
Cai 96.8
思路:
这道题和上一道题相似,但是有不同:
1.输入的为字符串,不能直接赋值,要用strcmp(s1,s2)
2.是顺序输出,为尾插法
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct stu_data { //使用typedef相当于把struct stu_data换一个名字,换成data
char name[20];
double num;
struct stu_data *next;
} data;
data *creatchain() {
data *head = NULL;
data *tail = NULL;
char name[20];
double num;
while (1) {
scanf("%s %lf", name, &num);
if (num == -1) {
break;
}
data *newNode = (data *)malloc(sizeof(data));
strcpy(newNode->name, name); //存储字符串
newNode->num = num;
newNode->next = NULL;
if (head == NULL) { //插在头部
head = newNode;
} else { //插在中间
tail->next = newNode;
}
tail = newNode;
}
return head;
}
//遍历链表
void traverseAndPrint(data *head) {
data *current = head;
while (current != NULL) {
printf("%s %.1f\n", current->name, current->num);
current = current->next;
}
}
int main() {
data *head = creatchain();
traverseAndPrint(head);
}
7-9 sdut-C语言实验-单链表的顺序建立与结点的删除
题目:
输入n个整数,先按照数据输入的顺序建立一个带头结点的单链表,再输入一个数据m,将单链表中的值为m的结点全部删除。分别输出建立的初始单链表和完成删除后的单链表。
输入格式:
第一行输入数据个数n(1<=n<=15);
第二行依次输入n个整数;
第三行输入欲删除数据m。
输出格式:
第一行输出原始单链表的长度;
第二行依次输出原始单链表的数据;
第三行输出完成删除后的单链表长度;
第四行依次输出完成删除后的单链表数据。
From:Teacher Wang
输入样例:
10
56 25 12 33 66 54 7 12 33 12
12
输出样例:
10
56 25 12 33 66 54 7 12 33 12
7
56 25 33 66 54 7 33
思路:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int num;
struct Node *next;
};
//创建链表,尾插法
struct Node *create_new(int n) {
struct Node *head, *tail, *p;
head = tail = NULL;
for (int i = 1; i <= n; i++) {
int num;
scanf("%d", &num);
p = (struct Node *)malloc(sizeof(struct Node));
p->num = num;
p->next = NULL;
if (head == NULL) {
head = p;
} else {
tail->next = p;
}
tail = p;
}
return head;
}
//删除指定链表
struct Node *delet_node(struct Node *head, int num) {
struct Node *p, *q;
q = p = head;
while (p != NULL) {
if (p->num == num) {
if (p == head) {
head = p->next;
free(q);
q = p = head;
} else {
q->next = p->next;
free(p);
p = q->next;
}
} else {
q = p;
p = p->next;
}
}
return head;
}
//遍历链表
void print_node(struct Node *head) {
struct Node *p = head;
while (p != NULL) {
if(p==head){
printf("%d", p->num);
p=p->next;
}
else{
printf(" %d", p->num);
p = p->next;
}
}
}
int count_node(struct Node *head) {
struct Node *p = head;
int count = 0;
while (p != NULL) {
count++;
p = p->next;
}
return count;
}
int main() {
int n, num;
scanf("%d", &n);
printf("%d\n", n);
struct Node *head = create_new(n);
print_node(head);
printf("\n");
scanf("%d", &num);
struct Node *newhead = delet_node(head, num);
printf("%d\n", count_node(newhead));
print_node(newhead);
}