第二章 线性表
1.选择题
(1)(2)
答案:BA
(3)
(4)(5)(6)
答案:ADB
(7)
(8)
答案:A
(9)
(10)
答案:D
(11)
(12)(13)(14)
答案:DDA
(15)
2.算法设计题
(1)
cppvoid MergeList_L(LinkList &La, LinkList &Lb, LinkList &Lc) { // 初始化指针 pa = La->next; // pa 指向 La 的第一个数据结点 pb = Lb->next; // pb 指向 Lb 的第一个数据结点 // 使用 La 的头结点作为 Lc 的头结点 Lc = pc = La; // 遍历两个链表,直到其中一个遍历完 while (pa && pb) { // 如果 pa 的数据较小,将 pc 移动到新的尾结点,pa 后移指向下一个结点 if (pa->data < pb->data) { pc->next = pa; pc = pa; // pc 移动到新的尾结点 pa = pa->next; // pa 后移 } // 如果 pb 的数据较小,将 pb 结点链接到 pc 后面(新的尾结点),pb 后移指向下一个结点 else if (pa->data > pb->data) { pc->next = pb; pc = pb; // pc 移动到新的尾结点 pb = pb->next; // pb 后移 } // 如果数据相等,取 La 的元素,删除 Lb 的元素 else { pc->next = pa; pc = pa; // pc 移动到新的尾结点 pa = pa->next; // pa 后移 q = pb->next; // 保存 pb 的下一个结点 delete pb; // 释放当前 pb 结点 pb = q; // pb 移动到下一个结点 } } // 将剩余部分链接到结果链表尾部 if (pa != NULL) { pc->next = pa; // 如果 pa 不为空,链接 pa 剩余部分 } else { pc->next = pb; // 否则链接 pb 剩余部分 } // 释放 Lb 的头结点 delete Lb; }
(2)
cpp// 函数功能:合并两个有序链表La和Lb,结果存储在Lc中(使用头插法,结果为降序) // 参数说明: // La, Lb: 待合并的两个有序链表(带头结点) // Lc: 合并后的结果链表 void union(LinkList& La, LinkList& Lb, LinkList& Lc) { // 初始化指针 pa = La->next; // pa指向La的第一个数据结点 pb = Lb->next; // pb指向Lb的第一个数据结点 // 使用La的头结点作为Lc的头结点 Lc = pc = La; Lc->next = NULL; // 初始化Lc为空链表 // 循环处理,直到两个链表都遍历完 while (pa || pb) { // 选择较小的结点(或剩余结点) if (!pa) { // 如果La已遍历完//if (!pa)等价于 if (pa == NULL) q = pb; // 取Lb的当前结点 pb = pb->next; // pb指针后移 } else if (!pb) { // 如果Lb已遍历完 q = pa; // 取La的当前结点 pa = pa->next; // pa指针后移 } // 比较两个链表的当前结点 else if (pa->data <= pb->data) { // La的结点值较小或相等 q = pa; // 取La的当前结点 pa = pa->next; // pa指针后移 } else { // Lb的结点值较小 q = pb; // 取Lb的当前结点 pb = pb->next; // pb指针后移 } // 将选中的结点插入到Lc的头部(头插法) q->next = Lc->next; // 新结点的next指向原Lc的第一个结点 Lc->next = q; // Lc的头结点指向新结点 } // 释放Lb的头结点 delete Lb; }
(3)
cpp// 函数功能:求两个有序链表La和Lb的交集,结果存储在Lc中 // 参数说明: // La, Lb: 输入的两个有序链表(带头结点) // Lc: 输出的结果链表 void Mix(LinkList& La, LinkList& Lb, LinkList& Lc) { // 初始化工作指针 pa = La->next; // pa指向La的第一个数据结点 pb = Lb->next; // pb指向Lb的第一个数据结点 // 使用La的头结点作为Lc的头结点 Lc = pc = La; // 遍历两个链表,直到其中一个遍历完 while (pa && pb) { if (pa->data == pb->data) { // 情况1:当前结点值相等,将pa结点加入结果链表 pc->next = pa; // 将pa链接到结果链表 pc = pa; // pc移动到新的尾结点 pa = pa->next; // pa后移 // 释放pb的当前结点(因为值相等,只需保留一个) q = pb; pb = pb->next; delete q; } else if (pa->data < pb->data) { // 情况2:pa结点值较小,直接释放pa结点 q = pa; pa = pa->next; delete q; } else { // 情况3:pb结点值较小,直接释放pb结点 q = pb; pb = pb->next; delete q; } } // 释放La的剩余结点(如果有) while (pa) { q = pa; pa = pa->next; delete q; } // 释放Lb的剩余结点(如果有) while (pb) { q = pb; pb = pb->next; delete q; } // 设置结果链表的尾结点 pc->next = NULL; // 释放Lb的头结点(可选) delete Lb; }
(4)
cpp// 函数功能:求两个递增有序单链表的差集 A - B,结果存储在链表 A 中 // 参数说明: // A, B: 两个带头结点的递增有序单链表,分别存储一个集合 // n: 结果集合元素个数的引用,调用时传入一个整型变量 void Difference(LinkedList A, LinkedList B, int &n) { // 初始化工作指针 p = A->next; // p 指向链表 A 的第一个数据结点 q = B->next; // q 指向链表 B 的第一个数据结点 head = A; // head 指向 p 的前驱结点(即 A 的头结点) n = 0; // 初始化计数器(引用可以直接赋值) // 同步遍历两个链表,直到其中一个遍历完 while (p != NULL && q != NULL) { if (p->data < q->data) { // 情况1:A 的当前结点值小于 B 的当前结点值 // 该结点属于差集,保留并继续处理 head = p; // head 指针后移,保持指向 p 的前驱 p = p->next; // p 指针后移 n++; // 差集元素个数加1(直接使用 n,不需要解引用) } else if (p->data > q->data) { // 情况2:A 的当前结点值大于 B 的当前结点值 // B 需要继续向后查找可能相等的结点 q = q->next; // q 指针后移 } else { // 情况3:A 和 B 的当前结点值相等 // 该结点不属于差集,需要从 A 中删除 head->next = p->next; // 将前驱结点的 next 指向 p 的后继结点 // 删除当前结点 p u = p; // 保存要删除的结点 p = p->next; // p 指针后移 delete u; // 释放被删除结点的内存 } } // 循环结束后,如果 A 还有剩余结点,它们都属于差集 while (p != NULL) { n++; // 差集元素个数加1 p = p->next; // 继续遍历 A 的剩余结点 } }
(6)
cpp// 函数功能:在单链表中查找最大值 // 参数说明:L是带头结点的单链表 // 返回值:链表中最大的元素值,若链表为空则返回NULL int Max(LinkList L) { // 检查链表是否为空(只有头结点) if (L->next == NULL) { return NULL; } // 初始化指针 LNode *pmax = L->next; // 假设第一个结点为最大值 LNode *p = L->next->next; // 从第二个结点开始遍历 // 遍历链表查找最大值 while (p != NULL) { // 如果当前结点值大于已知最大值 if (p->data > pmax->data) { pmax = p; // 更新最大值指针 } p = p->next; // 移动到下一个结点 } // 返回最大值结点的数据 return pmax->data; }
(7)
cpp// 函数功能:逆置带头结点的单链表 // 参数说明:L - 带头结点的单链表(引用传递) void inverse(LinkList &L) { // 初始化指针 LNode *p = L->next; // p指向链表第一个结点 L->next = NULL; // 将头结点的next置空,准备重建链表 // 遍历原链表,逐个结点逆置 while (p != NULL) { LNode *q = p->next; // q临时保存p的后继结点 // 将当前结点p插入到新链表的头部(头结点之后) p->next = L->next; // 将p的next指向原头结点的后继 L->next = p; // 头结点指向新的首元结点 p = q; // p移动到原链表的下一个结点 } }
(8)
cppvoid delete(LinkList &L, int mink, int maxk) { if (L == NULL || L->next == NULL) return; // 空链表直接返回 LNode *pre = L; // pre始终指向当前结点的前驱 LNode *p = L->next; // p从首元结点开始遍历 while (p != NULL) { if (p->data > mink && p->data < maxk) { // 找到需要删除的结点 pre->next = p->next; // 跳过当前结点 LNode *temp = p; // 临时保存要删除的结点 p = p->next; // p指针后移 free(temp); // 释放内存 } else { // 不需要删除的结点 pre = p; p = p->next; } } }