目录
6-1 顺序表操作集 (20 分)
6-2 线性表元素的区间删除 (20 分)
6-3 单链表逆转 (20 分)
6-4 两个有序链表序列的合并 (15 分)
7-1 两个有序序列的中位数 (25 分)
7-2 数组循环左移 (20 分)
7-3 最长连续递增子序列 (20 分)
7-5 求链式线性表的倒数第K项 (20 分)
7-6 两个有序链表序列的合并 (20 分)
7-7 两个有序链表序列的交集 (20 分)
7-8 重排链表 (25 分)
7-9 链表去重 (25 分)
本题要求实现顺序表的操作集。
List MakeEmpty();
Position Find( List L, ElementType X );
bool Insert( List L, ElementType X, Position P );
bool Delete( List L, Position P );
其中List
结构定义如下:
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
各个操作函数的定义为:
List MakeEmpty()
:创建并返回一个空的线性表;
Position Find( List L, ElementType X )
:返回线性表中X的位置。若找不到则返回ERROR;
bool Insert( List L, ElementType X, Position P )
:将X插入在位置P并返回true。若空间已满,则打印“FULL”并返回false;如果参数P指向非法位置,则打印“ILLEGAL POSITION”并返回false;
bool Delete( List L, Position P )
:将位置P的元素删除并返回true。若参数P指向非法位置,则打印“POSITION P EMPTY”(其中P是参数值)并返回false。
#include
#include
#define MAXSIZE 5
#define ERROR -1
typedef enum {false, true} bool;
typedef int ElementType;
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
List MakeEmpty();
Position Find( List L, ElementType X );
bool Insert( List L, ElementType X, Position P );
bool Delete( List L, Position P );
int main()
{
List L;
ElementType X;
Position P;
int N;
L = MakeEmpty();
scanf("%d", &N);
while ( N-- ) {
scanf("%d", &X);
if ( Insert(L, X, 0)==false )
printf(" Insertion Error: %d is not in.\n", X);
}
scanf("%d", &N);
while ( N-- ) {
scanf("%d", &X);
P = Find(L, X);
if ( P == ERROR )
printf("Finding Error: %d is not in.\n", X);
else
printf("%d is at position %d.\n", X, P);
}
scanf("%d", &N);
while ( N-- ) {
scanf("%d", &P);
if ( Delete(L, P)==false )
printf(" Deletion Error.\n");
if ( Insert(L, 0, P)==false )
printf(" Insertion Error: 0 is not in.\n");
}
return 0;
}
/* 你的代码将被嵌在这里 */
6
1 2 3 4 5 6
3
6 5 1
2
-1 6
结尾无空行
FULL Insertion Error: 6 is not in.
Finding Error: 6 is not in.
5 is at position 0.
1 is at position 4.
POSITION -1 EMPTY Deletion Error.
FULL Insertion Error: 0 is not in.
POSITION 6 EMPTY Deletion Error.
FULL Insertion Error: 0 is not in.
结尾无空行
List MakeEmpty()
{
List L;
L = (List)malloc(sizeof(struct LNode));
L->Last = -1;
return L;
}
Position Find(List L, ElementType X)
{
Position i;
for (i = 0; i <= L->Last; i++)
if (L->Data[i] == X)
return i;
return ERROR;
}
bool Insert(List L, ElementType X, Position P)
{
if (L->Last == MAXSIZE - 1)
{
printf("FULL");
return false;
}
else if (P < 0 || P > L->Last + 1)
{
printf("ILLEGAL POSITION");
return false;
}
else
{
Position i;
for (i = L->Last; i >= P; i--)
L->Data[i + 1] = L->Data[i];
L->Last++;
L->Data[P] = X;
return true;
}
}
bool Delete(List L, Position P)
{
if (P < 0 || P > L->Last)
{
printf("POSITION %d EMPTY", P);
return false;
}
else
{
Position i;
for (i = P + 1; i <= L->Last; i++)
L->Data[i - 1] = L->Data[i];
L->Last--;
return true;
}
}
C语言中的bool类型
typedef enum { false, true } bool;
malloc
1、在调用malloc函数时需要进行强制类型转换。所转换的类型为 “ = ” 左边的变量的类型。
2、所申请的空间大小应为该变量的类型名。而非指向该类型的指针类型。
3、在被调用函数中,当函数结束时会清除变量的内存空间,而动态申请的内存空间会在程序结束时自动清除。
给定一个顺序存储的线性表,请设计一个函数删除所有值大于min而且小于max的元素。删除后表中剩余元素保持顺序存储,并且相对位置不能改变。
List Delete( List L, ElementType minD, ElementType maxD );
其中List
结构定义如下:
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
L
是用户传入的一个线性表,其中ElementType
元素可以通过>、==、<进行比较;minD
和maxD
分别为待删除元素的值域的下、上界。函数Delete
应将Data[]
中所有值大于minD
而且小于maxD
的元素删除,同时保证表中剩余元素保持顺序存储,并且相对位置不变,最后返回删除后的表。
#include
#define MAXSIZE 20
typedef int ElementType;
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
List ReadInput(); /* 裁判实现,细节不表。元素从下标0开始存储 */
void PrintList( List L ); /* 裁判实现,细节不表 */
List Delete( List L, ElementType minD, ElementType maxD );
int main()
{
List L;
ElementType minD, maxD;
int i;
L = ReadInput();
scanf("%d %d", &minD, &maxD);
L = Delete( L, minD, maxD );
PrintList( L );
return 0;
}
/* 你的代码将被嵌在这里 */
10
4 -8 2 12 1 5 9 3 3 10
0 4
结尾无空行
4 -8 12 5 9 10
结尾无空行
List Delete(List L, ElementType minD, ElementType maxD)
{
Position num = 0, i;
for (i = 0; i <= L->Last; i++)
if (L->Data[i] <= minD || L->Data[i] >= maxD)
L->Data[num++] = L->Data[i];
L->Last = num - 1;
return L;
}
算法
遍历顺序表中的每一个元素。
对每一个元素进行检查,判断是否在(minD,maxD)区间内,若在,则读取下一个元素;若不在,则把该元素以尾插法放在新的顺序表中。
思路与 “ 就地逆置一个表 ” 的思路比较相像。
本题要求实现一个函数,将给定的单链表逆转。
List Reverse( List L );
其中List
结构定义如下:
typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
L
是给定单链表,函数Reverse
要返回被逆转后的链表。
#include
#include
typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode List;
List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表 */
List Reverse( List L );
int main()
{
List L1, L2;
L1 = Read();
L2 = Reverse(L1);
Print(L1);
Print(L2);
return 0;
}
/* 你的代码将被嵌在这里 */
5
1 3 4 5 2
结尾无空行
1
2 5 4 3 1
结尾无空行
List Reverse(List L)
{
struct Node *p = NULL, *q = NULL;
while(L){
p = L->Next;
L->Next = q;
q = L;
L = p;
}
return q;
}
思路
遍历L,每一次都要把L中的第一个结点以头插法的方式插到新的q链表中。
List Reverse(List L)
{
if (L)
{
struct Node *p1, *p2;
p1 = L->Next;
L->Next = NULL;
while (p1)
{
p2 = p1->Next;
p1->Next = L;
L = p1;
p1 = p2;
}
}
return L;
}
第四个测试点
当L为空时,需要返回NULL。因而需要有一个 if (L) 的判断。
思路
带哨兵的单链表的就地逆置
本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列。
List Merge( List L1, List L2 );
其中List
结构定义如下:
typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
L1
和L2
是给定的带头结点的单链表,其结点存储的数据是递增有序的;函数Merge
要将L1
和L2
合并为一个非递减的整数序列。应直接使用原序列中的结点,返回归并后的带头结点的链表头指针。
#include
#include
typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode List;
List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表;空链表将输出NULL */
List Merge( List L1, List L2 );
int main()
{
List L1, L2, L;
L1 = Read();
L2 = Read();
L = Merge(L1, L2);
Print(L);
Print(L1);
Print(L2);
return 0;
}
/* 你的代码将被嵌在这里 */
3
1 3 5
5
2 4 6 8 10
结尾无空行
1 2 3 4 5 6 8 10
NULL
NULL
结尾无空行
List Merge(List L1, List L2)
{
struct Node *head = (struct Node *)malloc(sizeof(struct Node));
struct Node *p0 = head, *p1 = L1->Next, *p2 = L2->Next;
while (p1 && p2)
{
if (p1->Data < p2->Data)
{
p0->Next = p1;
p0 = p1;
p1 = p1->Next;
}
else
{
p0->Next = p2;
p0 = p2;
p2 = p2->Next;
}
}
if (!p1)
p0->Next = p2;
else
p0->Next = p1;
L1->Next = NULL;
L2->Next = NULL;
return head;
}
对题目的理解要到位
根据 “ 输出样例 ” 可以知道,题目的意思是将两个链表合并到第三个链表中。
形象地来讲就是把两个递增的链表中的结点按非递减的顺序 “ 挪 ” 到第三个链表中。也就是说,“ 挪 ”之后的链表将成为空链表。因而在merge函数中需要额外申请一块内存来记录第三个新链表的头结点。用head变量来记录新头结点的地址,最后返回head。
已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列A0,A1,⋯,AN−1的中位数指A(N−1)/2的值,即第⌊(N+1)/2⌋个数(A0为第1个数)。
输入分三行。第一行给出序列的公共长度N(0 在一行中输出两个输入序列的并集序列的中位数。 结尾无空行 结尾无空行 思路 该题其实就是在这2n个数中输出第n个最小的数。 设置两个变量 i 和 j ,分别遍历第一、二个序列,用变量 x 来记录当前读到的最大值,直到读到第n个数为止。输出 x 即可 本题要求实现一个对数组进行循环左移的简单函数:一个数组a中存有n(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向左移m(≥0)个位置,即将a中的数据由(a0a1⋯an−1)变换为(am⋯an−1a0a1⋯am−1)(最前面的m个数循环移至最后面的m个位置)。如果还需要考虑程序移动数据的次数尽量少,要如何设计移动的方法? 输入第1行给出正整数n(≤100)和整数m(≥0);第2行给出n个整数,其间以空格分隔。 在一行中输出循环左移m位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。 结尾无空行 结尾无空行 putchar ( 10 ) 与 putchar ( 32 ) putchar ( 10 ) : 回车 putchar ( 32 ) : 空格 m的取值 1、m小于n时:第一个输出的值是a[m] 2、m大于等于n时:第一个输出的值是a[m%n] 输出格式 当m==0时:只走第一个循环,第二个循环进不去,所以在第一个循环输出最后一个数之后不能再输出空格。 给定一个顺序存储的线性表,请设计一个算法查找该线性表中最长的连续递增子序列。例如,(1,9,2,5,7,3,4,6,8,0)中最长的递增子序列为(3,4,6,8)。 输入第1行给出正整数n(≤105);第2行给出n个整数,其间以空格分隔。 在一行中输出第一次出现的最长连续递增子序列,数字之间用空格分隔,序列结尾不能有多余空格。 结尾无空行 结尾无空行 变量解释 sign:标记最长连续递增子序列的最后一个元素的下标 len0:标记最长连续递增子序列的长度 思路 for循环用来遍历顺序表。 while循环用来将顺序表分为若干个递增的子序列;并且用 i 表示 当前子序列的最后一个元素的下标,len表示当前子序列的长度。 if条件句用来记录最长连续递增子序列的最后一个元素的下标及其长度,并用sign和len0来记录。 给定一系列正整数,请设计一个尽可能高效的算法,查找倒数第K个位置上的数字。 输入首先给出一个正整数K,随后是若干非负整数,最后以一个负整数表示结尾(该负数不算在序列内,不要处理)。 输出倒数第K个位置上的数据。如果这个位置不存在,输出错误信息 结尾无空行 结尾无空行 注意 该题必须自己设计链表,不能用顺序表。因为顺序表需要提前设置好规模,而题目并没有设定规模。假若使用动态顺序表,那么太麻烦,不如直接用链表。所以还是按照题目本身的意思来写最简便。 为了方便找到倒数第n个结点,设置变量len来记录链表的长度。 最后输出要判断n是否在合法范围内,即看看n是不是在1到len之间。 malloc malloc 函数在头文件 stdlib.h 中。 已知两个非降序链表序列S1与S2,设计函数构造出S1与S2合并后的新的非降序链表S3。 输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。 在一行中输出合并后新的非降序链表,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出 结尾无空行 结尾无空行 typedef 与 结构体 的共用 建议!!!在struct后面写上结构体标识符!!!起个名字不难!!!否则会出现warning! 模块化程序设计 初始化一个链表 读入一个链表 合并两个链表 输出一个链表 完整代码 已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。 输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。 在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出 结尾无空行 结尾无空行 交集算法 依次遍历两个链表。 若一链表的当前元素相较于另一个链表的当前元素小时,则该链表后移一个结点; 若两个元素值相同,则将两个结点中任意一个结点插入新链表当中,并且两个链表均后移一个结点。 注意 这里的交集并不是数学意义上的交集,因为链表中的元素值是非降序的,也就是说可能存在两个元素的值是相等的,因而链表本身就不是严格意义上的集合,所以这里的交集的意思指:两个链表中相同的部分。 给定一个单链表 L1→L2→⋯→Ln−1→Ln,请编写程序将链表重新排列为 Ln→L1→Ln−1→L2→⋯。例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。 每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址和结点总个数,即正整数N (≤105)。结点的地址是5位非负整数,NULL地址用−1表示。 接下来有N行,每行格式为: 其中 对每个测试用例,顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。 结尾无空行 结尾无空行 思路 三个部分:存数据、捋一遍表、按格式输出 注意 结点的定义:本身的地址、本身的数值、下一个节点的地址(数组下标即为其地址) 倒数第二个测试点:可能存在不在表中的数据被读入 c++版本 Link 给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。 输入在第一行给出 L 的第一个结点的地址和一个正整数 N(≤105,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 -1 来表示。 随后 N 行,每行按以下格式描述一个结点: 其中 首先输出去重后的链表,然后输出被删除的链表。每个结点占一行,按输入的格式输出。 结尾无空行 结尾无空行 judge规模!!!输出格式:
输入样例1:
5
1 3 5 7 9
2 3 4 5 6
输出样例1:
4
输入样例2:
6
-100 -10 1 1 1 1
-50 0 2 3 4 5
输出样例2:
1
答案:
#include
分析:
7-2 数组循环左移 (20 分)
输入格式:
输出格式:
输入样例:
8 3
1 2 3 4 5 6 7 8
输出样例:
4 5 6 7 8 1 2 3
答案:
#include
分析:
7-3 最长连续递增子序列 (20 分)
输入格式:
输出格式:
输入样例:
15
1 9 2 5 7 3 4 6 8 0 11 15 17 17 10
输出样例:
3 4 6 8
答案:
#include
分析:
7-5 求链式线性表的倒数第K项 (20 分)
输入格式:
输出格式:
NULL
。输入样例:
4 1 2 3 4 5 6 7 8 9 0 -1
输出样例:
7
答案:
#include
分析:
7-6 两个有序链表序列的合并 (20 分)
输入格式:
输出格式:
NULL
。输入样例:
1 3 5 -1
2 4 6 8 10 -1
输出样例:
1 2 3 4 5 6 8 10
答案:
#include
分析:
list ini()
{
node *p = (node *)malloc(sizeof(node));
p->next = NULL;
return p;
}
void read(list l)
{
node *p0 = l;
int x;
scanf("%d", &x);
while (x != -1)
{
node *p = (node *)malloc(sizeof(node));
p->data = x;
p->next = NULL;
p0->next = p;
p0 = p0->next;
scanf("%d", &x);
}
}
void merge(list l0, list l1, list l2)
{
node *p0 = l0, *p1 = l1->next, *p2 = l2->next;
while (p1 && p2)
{
if (p1->data < p2->data)
{
p0->next = p1;
p0 = p0->next;
p1 = p1->next;
}
else
{
p0->next = p2;
p0 = p0->next;
p2 = p2->next;
}
}
if (p1)
p0->next = p1;
else
p0->next = p2;
}
void print(list l)
{
node *p = l->next;
if (p)
{
int flag = 0;
while (p)
{
if (flag)
printf(" %d", p->data);
else
{
flag = 1;
printf("%d", p->data);
}
p = p->next;
}
}
else
printf("NULL");
}
#include
7-7 两个有序链表序列的交集 (20 分)
输入格式:
输出格式:
NULL
。输入样例:
1 2 5 -1
2 4 5 8 10 -1
输出样例:
2 5
答案:
#include
分析:
7-8 重排链表 (25 分)
输入格式:
Address Data Next
Address
是结点地址;Data
是该结点保存的数据,为不超过105的正整数;Next
是下一结点的地址。题目保证给出的链表上至少有两个结点。输出格式:
输入样例:
00100 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
输出样例:
68237 6 00100
00100 1 99999
99999 5 12309
12309 2 00000
00000 4 33218
33218 3 -1
答案:
#include
分析:
7-9 链表去重 (25 分)
输入格式:
地址 键值 下一个结点
地址
是该结点的地址,键值
是绝对值不超过104的整数,下一个结点
是下个结点的地址。输出格式:
输入样例:
00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854
输出样例:
00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1
答案:
#include
思路