Bootstrap

数据结构快速教程0—预备


数据结构快速教程0—预备

本文开启数据结构与算法的学习。数据结构快速教程系列旨在通过快速总结知识点,去粗取精,保留重点,并通过封装的方式给出系统通用的模板函数及其使用方法,能在考试/工程及今后学习实践中直接调用。本系列对标BUAA数据结构课程体系。希望能够伴随您一学期的数据结构课程,取得良好的效果。

预备知识

本系列全体代码都为C语言实现,确保要有一定的C语言基础。对于BUAA来说,数据结构与程序设计是高级语言程序设计的后续课程。确保要掌握基本的C语言语法,熟悉递归,以及一些最初等的数据结构,包括数组结构体链表。尤其是链表一定要在本系列学习前掌握。注意递归不是了解内容,而是必会必熟的最基本内容,否则可能达不到课程考核要求。推荐浙江大学翁恺老师的C语言慕课教程。

BUAA数据结构期末的要求是非常高的。

系列内容

包括基于BUAA知识体系的一套完整的数据结构简明教程。包括栈和队列、树、查找、排序、图五大部分。再包括教程之前的“第0章”预备和最后一章“选填”,本系列共7次教程。对于系列中的每一篇教程,内容涵盖了以下几点:

  • 基本知识。对于概念的定义、例子给出清晰的阐释。课本或者课件上的概念可能分布分散,描述深奥晦涩,本简明教程中全部采用“人话”,用自己的话清楚的说这是什么意思,能够看一遍就看懂并且记住。尤其是树/图那边概念非常多,查找排序那边算法非常多,非常需要重点集中,表述清楚。
  • 封装函数。对于已经有固定模板的函数,这里举几个例子:比如BFS/DFS遍历、层次遍历、栈和队列的进入转出等等基本内容,在考场上或者工程实践中自己重写一遍是很浪费时间的。尤其是BUAA数据结构期末,时间是非常紧张,根本不像大一上学C语言那样考试考一半全提前交卷走了的情况。因此,通篇一个main函数肯定是不行的。这是初学数据结构必须要改变的一个最基本的习惯。必须要多函数多任务进程,这就非常需要平时积累函数,进行函数封装,考试直接调函数,又快又准。我们的简明教程最大的特点就是这样,把所有可能遇到的题目情况全部收集起来进行不同功能的函数封装,考试直接调用。当然,这样也可能产生弊端。就是平时作业也直接复制粘贴教程上的函数,失去了自己实现算法的机会。理论上,只知道每个函数的功能,而不管里边算法细节,用的时候直接调用当然也可以,但是更建议第一遍自己实现一遍,然后后面熟练了就直接调用了。一开始可能没这个感受,因为一开始栈和队列这边函数相对比较简单。但是越到后面,比如树那边,树的DFS可能就要想很久,一个模板函数写下来就5分钟了,自己现场写的可能还有bug,考试肯定通过不了。因为BUAA数据结构期末的要求是非常高的。学习数据结构和原来C语言基础的最大区别就是,一定要封装函数
  • 编程习题。使用BUAA作业题,每题在相应教程章节后面都有解答。注意:仅供参考,仅供批判式学习,直接抄袭得不偿失。在“查找”一章还囊括了BUAA2024春大作业,可谓是本教程的一个亮点。代码后一般有重点解释供参考。代码全部改成了通俗易懂的思路和语言,而不是技巧性做法。
  • 科学拓展。除了基本函数,我们更提供一些考试可能遇到的拓展函数。这些函数的特点是:只要平时遇到了,考试直接会写,但是没遇到,考试直接完蛋。之前BUAA数据结构期末甚至有第一步input就用递归的。不会递归直接10分再见。因此,拓展函数是非常必要的。除此之外,树和图是本系列精心打造的精品内容。树中除了三种遍历,还介绍了层次遍历、中断遍历,考试非常经常用。这是一个很大的亮点。

预备习题—第一组

下面正式开始习题练习。首先检验预备内容,也就是C语言基础。从下一套(栈和队列)开始,我们用知识点、封装函数、例题相结合的方式,正式开始新内容学习。

1. 扩展字符A

【问题描述】
从键盘输入包含扩展符’-'的字符串,将其扩展为等价的完整字符,例如将a-d扩展为abcd,并输出扩展后的字符串。

要求:只处理[a-z]、[A-Z]、[0-9]范围内的字符扩展,即只有当扩展符前后的字符同时是小写字母、大写字母或数字,并且扩展符后的字符大于扩展符前的字符时才进行扩展,其它情况不进行扩展,原样输出。例如:a-R、D-e、0-b、4-B等字符串都不进行扩展。

【输入形式】
从键盘输入包含扩展符的字符串
【输出形式】
输出扩展后的字符串

【输入样例1】
ADEa-g-m02
【输出样例1】
ADEabcdefghijklm02

【输入样例2】
cdeT-bcd
【输出样例2】
cdeT-bcd

【样例说明】
将样例1的输入ADEa-g-m02扩展为:ADEabcdefghijklm02;样例2的输入cdeT-bcd中,扩展符前的字符为大写字母,扩展符后的字符为小写字母,不在同一范围内,所以不进行扩展。
【评分标准】
该题要求扩展字符,提交程序文件expand.c。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int judge(char a, char b);

int main()
{
	char str[100] = { 0 };
	scanf("%s", str);

	int i, j;
	for (i = 0; i < strlen(str); i++) {
		if (str[i] != '-') {
			printf("%c", str[i]);
		}
		int k = i + 1;
		if (str[k] == '-') {
			if (judge(str[i], str[i + 2]) == 1) {
				for (j = str[i] + 1; j < str[i + 2]; j++) {
					printf("%c", j);
				}
			}
			else {
				printf("-"); 
			}
		}
	}
	return 0;
}

int judge(char a, char b) {
	int cnt = 0;
	//let cnt go to 1
	if (a >= '0' && a <= '9' && b >= '0' && b <= '9') {
		cnt = 1;
	}
	if (a >= 'a' && a <= 'z' && b >= 'a' && b <= 'z') {
		cnt = 1;
	}
	if (a >= 'A' && a <= 'Z' && b >= 'A' && b <= 'Z') {
		cnt = 1;
	}

	//judge
	if (b < a) {
		cnt = 0;
	}

	return cnt;
}

judge的时候可以用isdigit/isalpha库函数。当时不知道。这两个函数用的非常多,一定要知道。

2. 表达式计算(支持空格、连乘、连除)

【问题描述】

从标准输入中读入一个整数算术运算表达式,如5 - 1 * 2 * 3 + 12 / 2 / 2 = 。计算表达式结果,并输出。

要求:
1、表达式运算符只有+、-、*、/,表达式末尾的’=’字符表示表达式输入结束,表达式中可能会出现空格;
2、表达式中不含圆括号,不会出现错误的表达式;
3、出现除号/时,以整数相除进行运算,结果仍为整数,例如:5/3结果应为1。

【输入形式】

在控制台中输入一个以’=’结尾的整数算术运算表达式。

【输出形式】

向控制台输出计算结果(为整数)。

【样例1输入】

5 - 1 * 2 * 3 + 12 / 2 / 2 =

【样例1输出】

2

【样例2输入】

500 =

【样例2输出】

500

【样例1说明】

输入的表达式为5 - 1 * 2 * 3 + 12 / 2 / 2 =,按照整数运算规则,计算结果为2,故输出2。

【样例2说明】

输入的表达式为500 = ,没有运算符参与运算,故直接输出500。

算法之一提示:
1、可以利用gets函数,读取整行表达式;
2、对于空格,可以考虑首先去除表达式中的所有空格
3、可以设一计数器用来记录已读取、但未参加运算的运算符的个数,根据该计数器来判断如何进行运算;
4、可以设计一函数:实现二元整数算术运算。

【评分标准】

该题要求输出整数表达式的计算结果,共有5个测试点。上传C语言文件名为example1c.c。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int calculate(char* s) {
	int result = 0;
	int tempResult = 0;
	int number = 0;
	char op = '+';
	while ((*s) != '=') {
		if (isspace(*s)) {
			s++;
			continue;
		}
		if (isdigit(*s)) {
			number = 0;
			while (isdigit(*s)) {
				number = *s - '0' + number * 10;
				s++;
			}
			switch (op) {
				case('+'): tempResult = number; break;
				case('-'): tempResult = -number; break;
				case('*'): tempResult *= number; break;
				case('/'): tempResult /= number; break;
			}				
		}
		else {
			if ((*s) == '+' || (*s) == '-') {
				result += tempResult;
				tempResult = 0;
			}
			
			op = (*s);
			s++;
		}
	}

	result += tempResult;
	return result;
}
 
int main()
{
	char expression[1024] = { 0 };
	fgets(expression, 1024, stdin);
	printf("%d\n", calculate(&expression));
	return 0;
}

3. 小数形式与科学计数法转换

【问题描述】

编写一个程序,将用小数表示的浮点数,转换成科学计数法的形式输出。输入的数据没有符号,小数点前后必有数字,且全为有效数据,即小数点后的末尾数字不为0;小数点前若只有一位数字,可以为0,否则小数点前的最高位数字不为0。

提示:以字符串形式保存相关数据。

【输入形式】

从控制台输入一小数,最后有回车换行符,所有输入的字符数不会超过100。

【输出形式】

以科学计数法形式输出数据。输出的数据由以下几部分构成:
1.底数部分是一个小数或整数,若为小数,则小数点前后必有数字,而且都为有效数字。即:小数点前只有一位大于0的数字,小数点后的末尾数字不能为0。若为整数,则只有一位数字,不带小数点。
2.必有小写字母“e”。
3.指数部分是一个整数,若大于等于0,则不带正号“+”。若小于0,则需要带负号“-”,且整数的最高位数字不为0。

【输入样例1】

0.000000000000002

【输出样例1】

2e-15

【输入样例2】

8.9845623489651700659

【输出样例2】

8.9845623489651700659e0

【输入样例3】

367298599999093453490394859509568659795603.4

【输出样例3】

3.672985999990934534903948595095686597956034e41

【样例说明】

以小数形式输入数据,然后转换成科学计数法形式输出。

【评分标准】

该题要求以科学计数法形式输出数据,提交程序文件名为notation.c。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main()
{
	char num[100] = { 0 };
	scanf("%s", num);
	int cnt;			//记得每种情况前初始化cnt
	int i;
	int get;

	if (num[0] == '0') {
		cnt = 0;
		//计数
		for (i = 0; i < strlen(num); i++) {
			if (num[i] == '.' || num[i] == '0') {
				cnt++;
			}
			else {
				get = i;  //此时的i值留下
				break;
			}
		}
		cnt--;			//cnt就是幂
		printf("%c", num[get]);
		i++;
		if (i < strlen(num)) {
			printf(".");
		}				
		while (i < strlen(num)) {
			printf("%c", num[i]);
			i++;
		}
		printf("e-%d", cnt);
	}
	else {
		cnt = -1;
		//计数
		for (i = 0; i < strlen(num); i++) {
			if (num[i] != '.') {
				cnt++;
			}
			else {
				break;
			}
		}

		//output
		printf("%c.", num[0]);
		for (i = 1; i < strlen(num); i++) {
			if (num[i] != '.') {
				printf("%c", num[i]);
			}
		}
		printf("e%d", cnt);
	}
	return 0;
}

4. 超长正整数的减法

【问题描述】
编写程序实现两个超长正整数(每个最长80位数字)的减法运算。

【输入形式】

从键盘读入两个整数,要考虑输入高位可能为0的情况(如00083)。

  1. 第一行是超长正整数A;
  2. 第二行是超长正整数B;

【输出形式】
输出只有一行,是长整数A减去长整数B的运算结果,从高到低依次输出各位数字。要求:若结果为0,则只输出一个0;否则输出的结果的最高位不能为0,并且各位数字紧密输出。
【输入样例】

234098
134098703578230056

【输出样例】
-134098703577995958

【样例说明】
进行两个正整数减法运算, 234098 -134098703578230056 = -134098703577995958。

【评分标准】
完全正确得20分,每个测试点4分,提交程序文件名为subtract.c。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

void delZero(char str[], char dst[]);
void minus(char str[], char dst[]);

int main()
{
	char tempA[256] = { 0 };
	char tempB[256] = { 0 };
	char A[256] = { 0 };
	char B[256] = { 0 };

	gets(tempA);
	gets(tempB);
	delZero(tempA, A);
	delZero(tempB, B);

	if (strlen(A) > strlen(B)) {
		minus(A, B);
	}
	else if (strlen(A) == strlen(B) && strcmp(A, B) > 0) {
		minus(A,B);
	}
	else if(strcmp(A, B) == 0){
		printf("0");
	}
	else {
		printf("-");
		minus(B, A);
	}

	return 0;
}

void delZero(char str[], char dst[]) {
	int i, j = 0;
	//int begin = 0;
	i = 0;
	while (str[i++] == '0') {

	}
	int k = 0;
	for (j = i - 1; j < strlen(str); j++) {
		dst[k++] = str[j];
	}
	dst[k] = '\0';
}

void minus(char str[], char dst[]) {
	//str is longer than dst
	int len1 = strlen(str);
	int len2 = strlen(dst);
	int i, j;
	int digit = 0;
	int add = 0;

	for (i = len1 - 1, j = len2 - 1; j >= 0; i--, j--) {
		digit = str[i] - dst[j] + add;
		//借位
		if (digit >= 0) {
			add = 0;
		}
		else{
			add = -1;
			digit = 10 + digit;
		}
		str[i] = digit + '0';
	}

	if (add == 0) {
		while (str[0] == '0') {
			for (i = 0; i < strlen(str); i++) {
				str[i] = str[i + 1];
			}
		}
		printf("%s", str);
	}
	else {
		while (add != 0 && i != -1) {
			digit = str[i] - '0' + add;
			if (digit >= 0) {
				add = 0;
			}
			else {
				add = -1;
				digit = 10 + digit;
			}
			str[i] = digit + '0';
			i--;
		}
		
		while (str[0] == '0') {
			for (i = 0; i < strlen(str); i++) {
				str[i] = str[i + 1];
			}
		}
		printf("%s", str);
	}
}

5. 全排列数的生成

【问题描述】输入整数N( 1 <= N <= 10 ),生成从1~N所有整数的全排列。
【输入形式】输入整数N。
【输出形式】输出有N!行,每行都是从1~N所有整数的一个全排列,各整数之间以空格分隔。各行上的全排列不重复。输出各行遵循“小数优先”原则, 在各全排列中,较小的数尽量靠前输出。如果将每行上的输出看成一个数字,则所有输出构成升序数列。具体格式见输出样例。
【样例输入1】1
【样例输出1】1
【样例说明1】输入整数N=1,其全排列只有一种。
【样例输入2】3
【样例输出2】
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
【样例说明2】输入整数N=3,要求整数1、2、3的所有全排列, 共有N!=6行。且先输出1开头的所有排列数,再输出2开头的所有排列数,最后输出3开头的所有排列数。在以1开头的所有全排列中同样遵循此原则。
【样例输入3】10
【样例输出3】
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 10 9
1 2 3 4 5 6 7 9 8 10
1 2 3 4 5 6 7 9 10 8
1 2 3 4 5 6 7 10 8 9
1 2 3 4 5 6 7 10 9 8
1 2 3 4 5 6 8 7 9 10
1 2 3 4 5 6 8 7 10 9
1 2 3 4 5 6 8 9 7 10
1 2 3 4 5 6 8 9 10 7
……………………
【样例说明3】输入整数N=10,要求整数1、2、3、……、10的所有全排列。上例显示了输出的前10行。
【运行时限】要求每次运行时间限制在20秒之内。超出该时间则认为程序错误。提示:当N增大时,运行时间将急剧增加。在编程时要注意尽量优化算法,提高运行效率。
【评分标准】该题要求输出若干行整数。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void generatePermutation(int num[], int start, int len);
void printArray(int num[], int len);
void swap(int* a, int* b);
void sort(int num[], int start, int len);
void copy(int* arr1, int* arr2, int len);

int main() {
	int len;
	scanf("%d", &len);
	int num[len];
	int i;

	for (i = 0; i < len; i++) {
		num[i] = i + 1;
	}
	generatePermutation(num, 0, len);
}

void generatePermutation(int num[], int start, int len) {
	int* num1 = (int*)malloc(sizeof(int) * len);
	copy(num, num1, len);	//现在num1和num完全一样

	sort(num1, start, len);
	if (len == start) {
		printArray(num, len);
		copy(num, num1, len);
		free(num1);
	}
	else {
		int i;
		for (i = start; i < len; i++) {
			swap(&num1[start], &num1[i]);
			generatePermutation(num1, start + 1, len);
			swap(&num1[start], &num1[i]);//回溯
		}
	}
}

void printArray(int num[], int len) {
	int i;
	for (i = 0; i < len; i++) {
		printf("%d ", num[i]);
	}
	printf("\n");
}

void swap(int* a, int* b) {
	int swap = *a;
	*a = *b;
	*b = swap;
}

void sort(int num[], int start, int len) {
	int i, j;
	for (i = start; i < len; i++) {
		for (j = i + 1; j < len; j++) {
			if (num[j] < num[i]) {
				swap(&num[j], &num[i]);
			}
		}
	}
}

void copy(int* arr1, int* arr2, int len) {
	int i, j;
	for (i = 0; i < len; i++) {
		arr2[i] = arr1[i];
	}
}

预备习题—第二组

1. 五子棋危险判断

【问题描述】

已知两人分别执白棋和黑棋在一个围棋棋盘上下五子棋,若同一颜色的棋子在同一条横行、纵行或斜线上连成5个棋子,则执该颜色棋子的人获胜。编写程序读入某一时刻下棋的状态,并判断是否有人即将获胜,即:同一颜色的棋子在同一条横行、纵列或斜线上连成4个棋子,且该4个棋子的两端至少有一端为空位置。
输入的棋盘大小是19×19,用数字0表示空位置(即没有棋子),用数字1表示该位置下了一白色棋子,用数字2表示该位置下了一黑色棋子。假设同一颜色的棋子在同一条横行、纵列或斜线上连成的棋子个数不会超过4个,并且最多有一人连成线的棋子个数为4。

【输入形式】

从控制台输入用来表示棋盘状态的数字0、1或2;每行输入19个数字,各数字之间以一个空格分隔,每行最后一个数字后没有空格;共输入19行表示棋盘状态的数字。

【输出形式】

若有人即将获胜,则先输出即将获胜人的棋子颜色(1表示白色棋子,2表示黑色棋子),然后输出英文冒号:,最后输出连成4个棋子连线的起始位置(棋盘横行自上往下、纵列自左往右从1开始计数,横行最小的棋子在棋盘上的横行数和纵列数作为连线的起始位置,若在同一行上,则纵列数最小的棋子位置作为起始位置,两数字之间以一个英文逗号,作为分隔符)。
若没有人获胜,则输出英文字符串:No。
无论输出什么结果,最后都要有回车换行符。

【输入样例1】

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 2 0 1 1 2 0 0 0 0 0 0 0
0 0 0 0 0 2 1 1 1 1 2 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 2 1 2 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 2 2 0 0 0 0 0 0 0 0
0 0 0 0 0 2 0 1 0 0 2 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

【输出样例1】

1:9,8

【输入样例2】

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 2 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 2 2 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

【输出样例2】

No

【样例说明】

在输入的样例1中,执白棋(数字1表示)的人即将获胜,连成4个棋子且有一端为空的起始位置在第9行第8列,所以输出1:9,8。
在输入的样例2中,还没有同一颜色的棋子连成4个,所以无人即将获胜,直接输出No。

【评分标准】

该题要求判断五子棋的棋盘状态,提交程序文件名为chess.c。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void input(int(*arr)[19], int num);
int judge(int arr[19][19], int num);

int main()
{
	int chess[19][19] = { 0 };
	input(chess, 19);
	int judge1 = judge(chess, 1);
	int judge2 = judge(chess, 2);
	if (judge1 == 0 && judge2 == 0) {
		printf("No\n");
	}

	return 0;
}

void input(int (*arr)[19], int num) {
	int i, j;
	for (i = 0; i < num; i++) {
		for (j = 0; j < num; j++) {
			scanf("%d", &arr[i][j]);
		}
	}
}

int judge(int arr[19][19], int num) {
	//从棋盘中找是否存在四个棋子在同一行、纵列或斜线上
	//num表示棋子的颜色
	int flag = 0;
	int i, j;

	//判断行四连
	for (i = 0; i < 19; i++) {
		for (j = 0; j < 16; j++) {
			if (arr[i][j] == num && arr[i][j + 1] == num && arr[i][j + 2] == num && arr[i][j + 3] == num) {
				if (j != 0 && arr[i][j - 1] == 0) {
					flag = 1;
					printf("%d:%d,%d\n", num, i + 1, j + 1);
					break;
				}

				if (j != 15 && arr[i][j + 4] == 0) {
					flag = 1;
					printf("%d:%d,%d\n", num, i + 1, j + 1);
					break;
				}
			}
		}
	}

	//判断列四连
	for (j = 0; j < 19; j++) {
		for (i = 0; i < 16; i++) {
			if (arr[i][j] == num && arr[i + 1][j] == num && arr[i + 2][j] == num && arr[i + 3][j] == num) {
				if (i != 0 && arr[i - 1][j] == 0) {
					flag = 1;
					printf("%d:%d,%d\n", num, i + 1, j + 1);
					break;
				}

				if (i != 15 && arr[i + 4][j] == 0) {
					flag = 1;
					printf("%d:%d,%d\n", num, i + 1, j + 1);
					break;
				}
			}
		}
	}

	//判断主斜线
	for (i = 0; i < 16; i++) {
		for (j = 0; j < 16; j++) {
			if (arr[i][j] == num && arr[i + 1][j + 1] == num && arr[i + 2][j + 2] == num && arr[i + 3][j + 3] == num) {
				if (i != 0 && j != 0 && arr[i - 1][j - 1] == 0) {
					flag = 1;
					printf("%d:%d,%d\n", num, i + 1, j + 1);
					break;
				}

				if (i != 15 && j != 15 && arr[i + 4][j + 4] == 0) {
					flag = 1;
					printf("%d:%d,%d\n", num, i + 1, j + 1);
					break;
				}
			}
		}
	}

	//判断副斜线
	for (j = 3; j < 19; j++) {
		for (i = 0; i < 16; i++) {
			if (arr[i][j] == num && arr[i + 1][j - 1] == num && arr[i + 2][j - 2] == num && arr[i + 3][j - 3] == num) {
				if (i != 0 && j != 18 && arr[i - 1][j + 1] == 0) {
					flag = 1;
					printf("%d:%d,%d\n", num, i + 1, j + 1);
					break;
				}

				if (i != 15 && j != 3 && arr[i + 4][j - 4] == 0) {
					flag = 1;
					printf("%d:%d,%d\n", num, i + 1, j + 1);
					break;
				}
			}
		}
	}

	if (flag == 0) {
		return 0;
	}
	else {
		return 1;
	}
}

2. 字符串替换(新)

【问题描述】

编写程序将一个指定文件中某一字符串替换为另一个字符串。要求:(1)被替换字符串若有多个,均要被替换;(2)指定的被替换字符串,大小写无关。

【输入形式】

给定文件名为filein.txt。从控制台输入两行字符串(不含空格,行末尾都有回车换行符),分别表示被替换的字符串和替换字符串。

【输出形式】

将替换后的结果输出到文件fileout.txt中。

【样例输入】

从控制台输入两行字符串:

in

out

文件filein.txt的内容为:

#include <stdio.h>

void main()

{

FILE * IN;

if((IN=fopen(“in.txt”,“r”))==NULL)

{

​ printf(“Can’t open in.txt!”);

​ return;

}

fclose(IN);

}

【样例输出】

文件fileout.txt的内容应为:

#outclude <stdio.h>

void maout()

{

FILE * out;

if((out=fopen(“out.txt”,“r”))==NULL)

{

​ prouttf(“Can’t open out.txt!”);

​ return;

}

fclose(out);

}

【样例说明】

输入的被替换字符串为in,替换字符串为out,即将文件filein.txt中的所有in字符串(包括iN、In、IN字符串)全部替换为out字符串,并输出保存到文件fileout.txt中。

【评分标准】

该题要求得到替换后的文件内容,共有5个测试点。上传C语言文件名为replace.c。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <ctype.h> // 引入ctype.h来使用tolower函数

void replace(char line[], const char* fdChar, const char* rpChar);

int main()
{
    FILE* fp = fopen("filein.txt", "r");
    FILE* fp1 = fopen("fileout.txt", "w");

    char findChar[10] = { 0 };
    char replaceChar[10] = { 0 };
    scanf("%s", findChar);
    scanf("%s", replaceChar);

    char line[100] = { 0 };
    while (fgets(line, sizeof(line), fp) != NULL) {
        replace(line, findChar, replaceChar);
        fputs(line, fp1);
    }

    fclose(fp);
    fclose(fp1);

    return 0;
}

void replace(char line[], const char* fdChar, const char* rpChar) {
    char newLine[100] = { 0 };                      // 新建一个字符串用于存储替换后的结果
    int i, j, k;
    for (i = 0, k = 0; line[i] != '\0'; i++) {
        int match = 1;                              // 假设找到了匹配的字符串
        for (j = 0; fdChar[j] != '\0'; j++) {
            // 检查是否匹配,忽略大小写
            if (tolower(line[i + j]) != tolower(fdChar[j])) {
                match = 0;
                break;
            }
        }
        if (match) {
            // 如果找到匹配的字符串,替换之
            for (j = 0; rpChar[j] != '\0'; j++) {
                newLine[k++] = rpChar[j];
            }
            i += strlen(fdChar) - 1; // 跳过被替换的字符串
        }
        else {
            newLine[k++] = line[i];
            // 复制当前字符
        }
    }
    newLine[k] = '\0';
    strcpy(line, newLine);
}

3. 加密文件

【问题描述】有一种加密方法为:其使用一个字母串(可以含重复字母,字母个数不超过50)作为密钥。假定密钥单词串为feather,则先去掉密钥单词中的重复字母得到单词串feathr,然后再将字母表中的其它字母以反序追加到feathr的后面:

feathrzyxwvusqponmlkjigd

加密字母的对应关系如下:

abcdefghijklmnopqrstuvwxyz
feathrzyxwvusqponmlkjigdcb

其中第一行为原始英文字母,第二行为对应加密字母。其它字符不进行加密。编写一个程序,用这种密码加密文件。假定要加密的文件名为encrypt.txt及加密后的文件名为output.txt,并假定输入文件中字母全为小写字母,并且输入密钥也全为小写字母。

【输入形式】从标准输入中输入密钥串,并从文件encrypt.txt中读入要加密的内容。
【输出形式】加密后结果输出到文件output.txt中。
【样例输入】
feather
和文件encrypt.txt中内容,例如被加密的文件encrypt.txt中内容为:
c language is wonderful.
【样例输出】加密后output.txt文件中内容为:
a ufqzjfzh xl gpqthmrju.
【样例说明】首先将给定的密钥单词去除重复字母,然后按照上面的加密对应表对encrypt.txt文件内容进行加密即可得到加密后的文件,其中只对英文字母进行加密对换,并且假设encrypt.txt中的英文字母全是小写字母。

【评分标准】该题要求对文件进行加密,共有5个测试点。提交程序名为encrypt.c

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

char* delStandard(char del[]);
char* foundation(char sec[]);

int main()
{
	FILE* fp = fopen("encrypt.txt", "r");
	FILE* fp1 = fopen("output.txt", "w");

	char secret[16] = { 0 };
	char encrypt[256] = { 0 };
	scanf("%s", secret);
	getchar();
	fgets(encrypt, sizeof(char[256]), fp);
	//puts(encrypt);
	//puts(foundation(secret));
	char* newLetters = foundation(secret);

	for (int i = 0; i < strlen(encrypt); i++) {
		if (encrypt[i] >= 'a' && encrypt[i] <= 'z') {
			fprintf(fp1, "%c", newLetters[encrypt[i] - 'a']);
		}
		else {
			fprintf(fp1, "%c", encrypt[i]);
		}
	}

	fclose(fp);
	fclose(fp1);

	return 0;
}

char* delStandard(char del[]) {
	//函数的目的是,返回删除了del数组中字母的标准字母表
	static char letters[26] = { 0 };
	int i, j;
	i = 0;
	int len = strlen(del);
	char ltr = 'a';

	while (ltr <= 'z') {
		int flag = 1;
		for (j = 0; j < len; j++) {
			if (del[j] == ltr) {
				flag = 0;
				break;
			}
		}

		if (flag == 1) {
			letters[i++] = ltr;
		}
		ltr++;
	}

	return letters;
}

char* foundation(char sec[]) {
	//函数的目的是构建对应表
	//首先,删除sec中重复单词
	int i, j, k;
	for (i = 0; i < strlen(sec) - 1; i++) {
		for (j = i + 1; j < strlen(sec); ) {
			if (sec[i] == sec[j]) {
				for (k = j; k < strlen(sec); k++) {
					sec[k] = sec[k + 1];
				}
			}
			else {
				j++; 
			}
		}
	}

	//构造对应表
	static char secretString[26] = { 0 };
	//初始化,防止提前结束
	for (i = 0; i < 26; i++) {
		secretString[i] = 'a';
	}
	//重新赋值
	for (i = 0; i < strlen(sec); i++) {
		secretString[i] = sec[i];
	}
	char* temp = delStandard(sec);
	for (i = 25, j = 0; i >= strlen(sec); i--, j++) {
		secretString[i] = temp[j];
	}
	
	return secretString;
}

4. 通讯录整理

【问题描述】

读取一组电话号码簿(由姓名和手机号码组成),将重复出现的项删除(姓名和电话号码都相同的项为重复项,只保留第一次出现的项),并对姓名相同手机号码不同的项进行如下整理:首次出现的项不作处理,第一次重复的姓名后面加英文下划线字符_和数字1,第二次重复的姓名后面加英文下划线字符_和数字2,依次类推。号码簿中姓名相同的项数最多不超过10个。最后对整理后的电话号码簿按照姓名进行从小到大排序,并输出排序后的电话号码簿。

【输入形式】

先从标准输入读取电话号码个数,然后分行输入姓名和电话号码,姓名由不超过20个英文小写字母组成,电话号码由11位数字字符组成,姓名和电话号码之间以一个空格分隔,输入的姓名和电话号码项不超过100个。

【输出形式】

按照姓名从小到大的顺序分行输出最终的排序结果,先输出姓名再输出电话号码,以一个空格分隔。

【样例输入】

15

liping 13512345678

zhaohong 13838929457

qiansan 13900223399

zhouhao 18578294857

anhai 13573948758

liping 13512345678

zhaohong 13588339922

liping 13833220099

boliang 15033778877

zhaohong 13838922222

tianyang 18987283746

sunnan 13599882764

zhaohong 13099228475

liushifeng 13874763899

caibiao 13923567890

【样例输出】

anhai 13573948758

boliang 15033778877

caibiao 13923567890

liping 13512345678

liping_1 13833220099

liushifeng 13874763899

qiansan 13900223399

sunnan 13599882764

tianyang 18987283746

zhaohong 13838929457

zhaohong_1 13588339922

zhaohong_2 13838922222

zhaohong_3 13099228475

zhouhao 18578294857

【样例说明】

输入了15个人名和电话号码。其中第一项和第六项完全相同,都是“liping 13512345678”,将第六项删除,第一项保留;

第八项和第一项人名相同,电话不同,则将第八项的人名整理为liping_1;同样,第二项、第七项、第十项、第十三项的人名都相同,将后面三项的人名分别整理为:zhaohong_1、zhaohong_2和zhaohong_3。

最后将整理后的电话簿按照姓名进行从小到大排序,分行输出排序结果。

【评分标准】

该题要求编程实现通讯录的整理与排序,提交程序文件名为sort.c。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

typedef struct _list {
	char name[20];
	char call[12];
	int number;
	//本题要求,相同姓名,不同电话号码输出的时候
	//要按照输入的顺序依次输出。但是在排序时可能会
	//打乱一开始输入的先后顺序。因此,做一个排号是非常必要的。
}List;

void input(int cnt, List* list);
int check(int cnt, List* list);
void sort(int cnt, List* list);
void add(int cnt, List* list);
void output(int cnt, List* list);

int main()
{
	int cnt;
	List list[100] = { 0 };

	//input
	scanf("%d", &cnt);
	input(cnt, list);
	//printf("%s", list[1].name); 
	//puts(list[1].call);

	//查重
	cnt = check(cnt, list);
	//printf("%d\n", cnt);
	
	//先排序
	sort(cnt, list);
	//printf("%s", list[1].name); 

	//再添加尾缀
	add(cnt, list);
	//printf("%s", list[12].name);

	//output
	output(cnt, list);

	return 0;
}

void input(int cnt, List* list) {
	int i;
	for (i = 0; i < cnt; i++) {
		scanf("%s", list->name);
		scanf("%s", list->call);
		list->number = i;
		list++;
	}
}

int check(int cnt, List* list) {
	//查重删除
	int i, j, k;
	for (i = 0; i < cnt - 1; i++) {
		for (j = i + 1; j < cnt; j++) {
			if (strcmp(list[i].name, list[j].name) == 0 && strcmp(list[i].call, list[j].call) == 0) {
				for (k = j; k < cnt; k++) {
					strcpy(list[k].name, list[k + 1].name);
					strcpy(list[k].call, list[k + 1].call);
					list[k].number = list[k + 1].number;
				}
				cnt--;
			}
		}
	}

	return cnt;
}

void sort(int cnt, List* list) {
	//排序
	int i, j;
	for (i = 0; i < cnt - 1; i++) {
		for (j = i + 1; j < cnt; j++) {
			if (strcmp(list[i].name, list[j].name) > 0) {
				List temp = list[i];
				list[i] = list[j];
				list[j] = temp;
			}
		}
	}
}

void add(int cnt, List* list) {
	int i, j, k, t;
	int num = 1;

	//添加尾缀之前,要对重复出现的名字按照number序号重新排序
	for (i = 0; i < cnt - 1; i++) {
		j = i + 1;
		while (strcmp(list[i].name, list[j].name) == 0) {
			j++;
		}
		//对i,j之间的元素按照number从小到大重新排序
		for (k = i; k < j - 1; k++) {
			for (t = i + 1; t < j; t++) {
				if (list[k].number > list[t].number) {
					List swap = list[k];
					list[k] = list[t];
					list[t] = swap;
				}
			}
		}
	}

	//下面开始添加尾缀
	for (i = 0; i < cnt - 1; ) {
		num = 1; 
		j = i + 1;
		while (strcmp(list[i].name, list[j].name) == 0) {
			if (num < 10) {
				char arr[3] = { '_', num + '0', '\0' };
				strcat(list[j].name, arr);
				j++;
				num++;
			}
			else {
				//num == 10
				strcat(list[j].name, "10");
				num++;
				break;
			}
		}
		i += num;
		//i++;
	}
}

void output(int cnt, List* list) {
	int i;
	for (i = 0; i < cnt; i++) {
		printf("%s ", list[i].name);
		printf("%s\n\n", list[i].call);
	}
}

这个题相当于BUAA数据结构期末编程题第一题的削弱版。可以掂量一下难度。

5. 小型图书管理系统

【问题描述】
小明同学特别喜欢买书看书。由于书较多,摆放杂乱,找起来非常麻烦。这学期小明同学上了数据结构与程序设计课后,决定改变这种状况:用C开发一个小型图书管理系统。系统中包含的图书信息有:书名、作者、出版社、出版日期等。首先,图书管理系统对已有的书(原始书库,存放在一个文本文件中)按书名字典序进行(按书名中各字符的ASCII码值由小到大排序)摆放(即将原始无序的图书信息文件生成一个有序的文件,即新书库),以便查找。该管理系统可以对新书库中图书条目进行如下操作:
1.录入。新增书录入到书库中(即从输入中读入一条图书信息插入到已排序好的图按书文件相关位置处)
2.查找。按书名或书名中关键字信息在书库中查找相关图书信息,若有多本书,按字典序输出。
3.删除。输入书名或书名中关键字信息,从书库中查找到相关书并将其删除,并更新书库。
【输入形式】
原始的图书信息(原始书库)保存在当前目录下的books.txt中。
用户操作从控制台读入,首先输入操作功能序号(1代表录入操作,2代表查找操作,3代表删除操作,0代表将已更新的图书信息保存到书库中并退出程序),然后在下一行输入相应的操作信息(录入操作后要输入一条图书信息,查找和删除操作后只要输入书名或书名中部分信息)。程序执行过程中可以进行多次操作,直到退出(输入操作0)程序。
要求:
1、原始文件中的图书信息与录入的图书信息格式相同,每条图书信息都在一行上,包括书名(不超过50个字符)、作者(不超过20个字符)、出版社(不超过30个字符)和出版日期(不超过10个字符),只由英文字母和下划线组成,用一个空格分隔。图书信息总条数不会超过500.
2、下划线字符参加排序。
3、图书不会重名。
【输出形式】
进行录入和删除操作,系统会更新图书信息,但不会在控制台窗口显示任何信息。
进行查找操作后,将在控制台按书名字典序分行输出查找到的图书信息,书名占50个字符宽度,作者占20个字符宽度,出版社占30个字符宽度,出版日期占10个字符宽度,都靠左对齐输出。
最终按字典排序的图书信息保存在当前目录下的ordered.txt中,每条图书信息占一行,格式与查找输出的图书信息相同。
【样例输入】
假设books.txt中保存的原始图书信息为:
The_C_programming_language Kernighan Prentice_Hall 1988
Programming_in_C Yin_Bao_Lin China_Machine_Press 2013
Data_structures_and_Algorithm_Analysis_in_C Mark_Allen_Weiss Addison_Wesley 1997
ANSI_and_ISO_Standard_c Plauger Microsoft_Press 1992
Data_structures_and_program_design_in_C Robert_Kruse Pearson_Education 1997
Computer_network_architectures Anton_Meijer Computer_Science_Press 1983
C_programming_guidelines Thomas_Plum Prentice_Hall 1984
Data_structures_using_C Tenenbaum Prentice_Hall 1990
Operating_system_concepts Peterson Addison_Wesley 1983
Computer_networks_and_internets Douglas_E_Come Electronic_Industry 2017
用户控制台输入信息为:
1
Data_structures_and_C_programs Christopher Addison_Wesley 1988
2
structure
1
The_C_programming_tutor Leon_A_Wortman R_J_Brady 1984
2
rogram
3
rogramming
0
【样例输出】
用户输入“2 structure”后,控制台输出:

在这里插入图片描述

用户输入“2 rogram”后,控制台输出:

[外链图片转存中...(img-jU7IvG5h-1720185642318)]

ordered.txt文件内容为:
[外链图片转存中...(img-nohH91fx-1720185642318)]

【样例说明】
先读入books.txt中的10条图书信息,按照书名进行字典序排序;用户进行了五次操作,然后退出:第一次操作是插入了一条图书信息,这时有11条图书信息,按书名字典序排序为:
ANSI_and_ISO_Standard_c Plauger Microsoft_Press 1992
C_programming_guidelines Thomas_Plum Prentice_Hall 1984
Computer_network_architectures Anton_Meijer Computer_Science_Press 1983
Computer_networks_and_internets Douglas_E_Come Electronic_Industry 2017
Data_structures_and_Algorithm_Analysis_in_C Mark_Allen_Weiss Addison_Wesley 1997
Data_structures_and_C_programs Christopher Addison_Wesley 1988
Data_structures_and_program_design_in_C Robert_Kruse Pearson_Education 1997
Data_structures_using_C Tenenbaum Prentice_Hall 1990
Operating_system_concepts Peterson Addison_Wesley 1983
Programming_in_C Yin_Bao_Lin China_Machine_Press 2013
The_C_programming_language Kernighan Prentice_Hall 1988
第二次操作是查找书名包含structure的图书,有4本图书信息按照格式要求输出到屏幕;第三次操作又插入了一条图书信息,这时有12条图书信息;第四次操作查找书名包含rogram的图书,有6本图书信息按照格式要求输出到屏幕;第五次操作是删除书名包含rogramming的图书信息,有四条图书信息要删除,剩下八条图书信息;最后退出程序前将剩余的八条图书信息按照格式要求存储在ordered.txt文件中。
【评分标准】

该程序要求编写图书管理系统。提交程序文件名为books.c。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>

struct node{//节点的类型
    char name[100];
    char author[30];
    char publish[50];
    char date[20];
    struct node *next;//指向下一个节点的指针
};
//typedef : 数据类型重命名
typedef struct node node;
typedef struct node *node_list;

//int list_insert_pre_node_temp(node_list *head,node_list *p,int element);//指定结点的前插O(n)
int list_insert_pre_node(node_list p,char name[],char author[],char publish[],char date[]);//指定结点的前插O(1)
int list_insert_next_node(node_list p,char name[],char author[],char publish[],char date[]);//指定结点的后插

int list_delete_node_normal(node_list *head,node *p);//O(n)删除一个指定结点

void list_print(node_list temp);

node_list pubbleSort(node_list head);
int find_inf(char name[],char inf[]);

char name[100];
char author[30];
char publish[50];
char date[20];
char inf[100];

int main()
{
    FILE *sin,*sout;
    //sin=fopen("books.txt", "r");
    sin=fopen("books.txt", "r");
    sout=fopen("ordered.txt", "w");
    node_list head=(node *)malloc(sizeof(node));
    head->next=NULL;
    node *now,*tail=head;
    while((fscanf(sin,"%s%s%s%s",name,author,publish,date))!=EOF){
        //printf("%s %s %s %s\n",name,author,publish,date);
        now=(node *)malloc(sizeof(node));
        strcpy(now->name,name);
        strcpy(now->author,author);
        strcpy(now->publish,publish);
        strcpy(now->date,date);
        tail->next=now;
        tail=now;
    }
    tail->next=NULL;
    fclose(sin);
    //list_print(head);
    if(NULL!=head->next){
        head=pubbleSort(head);
        //list_print(head);
    }

    int op;
    while(1){
        scanf("%d",&op);
        if(op==1){//insert
            scanf("%s%s%s%s",name,author,publish,date);
            if(NULL==head->next){
                now=(node *)malloc(sizeof(node));
                strcpy(now->name,name);
                strcpy(now->author,author);
                strcpy(now->publish,publish);
                strcpy(now->date,date);
                head->next=now;
                tail=now;
                tail->next=NULL;
            }
            else{
                node *i=head->next;
                for(i;NULL!=i;i=i->next){
                    if(strcmp(i->name,name)>0){
                        list_insert_pre_node(i,name,author,publish,date);
                        //list_print(head);
                        break;
                    }
                    if(NULL==i->next){
                        list_insert_next_node(i,name,author,publish,date);
                        break;
                    }
                }
            }
        }
        else if(op==2){//find
            scanf("%s",inf);
            //printf("%s\n",inf);
            node *i=head->next;
            for(i;NULL!=i;i=i->next){
                if(find_inf(i->name,inf)){
                    printf("%-50s%-20s%-30s%s\n",i->name,i->author,i->publish,i->date);
                }
            }
        }
        else if(op==3){//delete
            scanf("%s",inf);
            node *i=head->next;
            for(i;NULL!=i;i=i->next){
                if(find_inf(i->name,inf)){
                    list_delete_node_normal(head,i);
                }
            }
        }
        else if(op==0){
            node_list temp=head;
            temp=temp->next;
            while(NULL!=temp){
                fprintf(sout,"%-50s%-20s%-30s%s\n",temp->name,temp->author,temp->publish,temp->date);
                temp=temp->next;
            }
            fclose(sout);
            break;
        }
    }
    return 0;
}

int find_inf(char name[],char inf[])
{
    int len_name=strlen(name);
    int len_inf=strlen(inf);
    for(int i=0;i<len_name;i++){
        if(name[i]==inf[0]){
            int look=0;
            while(look<len_inf){
                if(name[i+look]!=inf[look]){
                    break;
                }
                if(look==len_inf-1){
                    return 1;
                }
                look++;
            }
        }
    }
    return 0;
}

node_list pubbleSort(node_list head)
{
    node *i=head->next;
    for(i;NULL!=i;i=i->next){
        for(node *j=head->next;NULL!=j;j=j->next){
            if(strcmp(i->name,j->name)<0){
                node *temp=(node *)malloc(sizeof(node));
                strcpy(temp->name,i->name);
                strcpy(temp->author,i->author);
                strcpy(temp->publish,i->publish);
                strcpy(temp->date,i->date);

                strcpy(i->name,j->name);
                strcpy(i->author,j->author);
                strcpy(i->publish,j->publish);
                strcpy(i->date,j->date);

                strcpy(j->name,temp->name);
                strcpy(j->author,temp->author);
                strcpy(j->publish,temp->publish);
                strcpy(j->date,temp->date);
            }
        }
    }
    return head;
}

int list_insert_pre_node(node_list p,char name[],char author[],char publish[],char date[])//指定结点的前插O(1)
//偷天换日
{
    if(NULL==p) return 0;
    node *new_node=(node *)malloc(sizeof(node));
    if(NULL==new_node) return 0;
    new_node->next=p->next;
    p->next=new_node;
    strcpy(new_node->name,p->name);
    strcpy(new_node->author,p->author);
    strcpy(new_node->publish,p->publish);
    strcpy(new_node->date,p->date);
    strcpy(p->name,name);
    strcpy(p->author,author);
    strcpy(p->publish,publish);
    strcpy(p->date,date);
    return 1;
}

int list_insert_next_node(node_list p,char name[],char author[],char publish[],char date[])//指定结点的后插
{
    if(NULL==p) return 0;
    node *new_node=(node *)malloc(sizeof(node));
    if(NULL==new_node) return 0;

    strcpy(new_node->name,name);
    strcpy(new_node->author,author);
    strcpy(new_node->publish,publish);
    strcpy(new_node->date,date);
    new_node->next=p->next;
    p->next=new_node;
    return 1;
}

int list_delete_node_normal(node_list *head,node *p)//O(n)删除一个指定结点
{
    if(NULL==p) return 0;
    node_list pre;
    pre=head;
    while(pre->next!=p&&pre->next!=NULL){
        pre=pre->next;
    }
    if(pre->next!=NULL){
        pre->next=p->next;
        free(p);
    }
    return 1;
}

void list_print(node_list temp)
{
    temp=temp->next;
    while(temp!=NULL){
        printf("%s %s %s %s\n",temp->name,temp->author,temp->publish,temp->date);
        temp=temp->next;
    }
}

该题相当于BUAA数据结构期末编程题第一题的水平。

以上就是复习的全部内容。下一节栈和队列,我们将开启全新的数据结构之旅。

;