♻️ 更新习题2.23的注释,顺便将CFree的代码更新为与其他分支一致

This commit is contained in:
康建伟
2020-03-25 10:06:08 +08:00
parent 9bf5d0d060
commit 0efbc2bc1b
4 changed files with 355 additions and 230 deletions

View File

@@ -2,142 +2,188 @@
#include "../../../▲课本算法实现/▲01 绪论/Status.h" //**▲01 绪论**//
#include "../../../▲课本算法实现/▲02 线性表/04 SinglyLinkedList/SinglyLinkedList.c" //**▲02 线性表**//
/* 函数原型 */
Status Algo_2_23_1(LinkList La, LinkList *Lb, LinkList *Lc);
Status Algo_2_23_2(LinkList La, LinkList *Lb, LinkList *Lc);
/*
* 题2.23
*
* 方法一将La中的元素插入到Lb中然后让Lc指向Lb
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc);
/*
* 题2.23
*
* 方法二将La和Lb中的元素交替摘下并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc);
// 测试函数,打印元素
void PrintElem(LElemType_L e);
//测试函数,打印整型
int main(int argc, char *argv[])
int main(int argc, char* argv[])
{
LinkList La, Lb, Lc;
int i, mark;
if(InitList_L(&La) && InitList_L(&Lb) && InitList_L(&Lc)) //链表L创建成功
LinkList La, Lb, Lc;
int i;
// 0号单元存储的是数组长度
int a[] = {10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
int b[] = { 8, 2, 4, 6, 8, 10, 12, 14, 16};
// 准备测试数据
InitList_L(&La);
InitList_L(&Lb);
for(i = 1; i <= a[0]; i++) {
ListInsert_L(La, i, a[i]);
}
for(i = 1; i <= b[0]; i++) {
ListInsert_L(Lb, i, b[i]);
}
printf("La = ");
ListTraverse_L(La, PrintElem);
printf("\n");
printf("Lb = ");
ListTraverse_L(Lb, PrintElem);
printf("\n");
// 归并方法测试
// Algo_2_23_1(La, Lb, &Lc);
Algo_2_23_2(La, Lb, &Lc);
printf("Lc = ");
ListTraverse_L(Lc, PrintElem);
printf("\n");
return 0;
}
/*
* 题2.23
*
* 方法一将La中的元素插入到Lb中然后让Lc指向Lb
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc)
{
LinkList p, pb;
// 初始化Lc
InitList_L(Lc);
// 确保La和Lb存在
if(La == NULL || Lb == NULL || Lc == NULL)
{
for(i=1; i<=5; i++) //创建链表La和Lb
return ERROR;
}
pb = Lb;
// 先遍历La和Lb的共同部分
while(La->next != NULL && pb->next != NULL)
{
// 从La中摘下结点
p = La->next;
La->next = p->next;
// 将La中摘下的结点插入到Lb中
p->next = pb->next;
pb->next = p;
// 前进到原Lb中下一个结点的位置
pb = pb->next->next;
}
// 如果La有剩余但Lb已遍历到尽头则需要将La中剩余元素整体链接到Lb的尾部
if(pb->next == NULL && La->next != NULL)
{
pb->next = La->next;
La->next = NULL;
}
// 让Lc指向Lb的链表
(*Lc)->next = Lb->next;
Lb->next = NULL;
return OK;
}
/*
* 题2.23
*
* 方法二将La和Lb中的元素交替摘下并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc)
{
LinkList p, pc;
int flag; // 指挥当前应当摘下La中的元素还是摘下Lb中的元素
// 初始化Lc
InitList_L(Lc);
// 确保La和Lb存在
if(La == NULL || Lb == NULL || Lc == NULL)
{
return ERROR;
}
flag = 0;
pc = *Lc;
// 先遍历La和Lb的共同部分
while(La->next!=NULL && Lb->next!=NULL)
{
// 摘下La中的元素
if(flag==0)
{
// 摘下La中的元素
p = La->next;
La->next = p->next;
flag = 1;
}
// 摘下La中的元素
else
{
ListInsert_L(La, i, 2*i-1);
ListInsert_L(Lb, i, 2*i);
}
}
printf("验证题 2.23 的方法1输入 1 ,验证题 2.23 的方法2输入 2 ");
fflush(stdin);
scanf("%d", &mark);
printf("\n");
printf("创建好的链表为:\n");
printf("La = ");
ListTraverse_L(La, PrintElem);
printf("\n");
printf("Lb = ");
ListTraverse_L(Lb, PrintElem); //输出链表
printf("\n\n");
if(mark==1)
p = Lb->next;
Lb->next = p->next;
flag = 0;
}
// 将摘下的元素插入到Lc
pc->next = p;
pc = pc->next;
}
// 如果La已经遍历到尽头(Lb可能有剩余)
if(La->next==NULL)
{
printf("题 2.23 方法1 验证...\n");
Algo_2_23_1(La, &Lb, &Lc);
}
if(mark==2)
// 摘下Lb中可能剩余的所有元素
p = Lb->next;
Lb->next = NULL;
pc->next = p;
}
// 如果La有剩余(Lb一定遍历到尽头了否则上面的while循环会继续执行)
else
{
printf("题 2.23 方法2 验证...\n");
Algo_2_23_2(La, &Lb, &Lc);
}
printf("归并La和Lb为Lc = ");
ListTraverse_L(La, PrintElem);
printf("\n\n");
return 0;
// 摘下La中剩余的元素
p = La->next;
La->next = NULL;
pc->next = p;
}
return OK;
}
/*━━━━━━━━━━━┓
┃题2.23:归并两个单链表┃
┗━━━━━━━━━━━*/
/* 方法一:顺序链接 */
Status Algo_2_23_1(LinkList La, LinkList *Lb, LinkList *Lc)
// 测试函数,打印元素
void PrintElem(LElemType_L e)
{
LinkList prea, pa, pb;
if(!La || !(*Lb) || (!La->next && !(*Lb)->next))//La或Lb有一个不存在或两个均为空表时合并错误
return ERROR;
*Lc = La; //利用A的头结点作C的头结点
prea = La;
pa = La->next;
pb = (*Lb)->next;
while(pa && pb)
{
(*Lb)->next = pb->next;
prea = pa;
pa = pa->next;
prea->next = pb;
pb->next = pa;
prea = pb;
pb = (*Lb)->next;
}
if(!pa) //Lb还有剩余
prea->next = pb;
free((*Lb));
*Lb = NULL;
return OK;
}
/*━━━━━━━━━━━┓
┃题2.23:归并两个单链表┃
┗━━━━━━━━━━━*/
/* 方法二:交替链接 */
Status Algo_2_23_2(LinkList La, LinkList *Lb, LinkList *Lc)
{
LinkList cur, pa, pb;
int i = 0;
if(!La || !(*Lb) || (!La->next && !(*Lb)->next))//La或Lb有一个不存在或两个均为空表时合并错误
return ERROR;
*Lc = La; //利用A的头结点作C的头结点
cur = (*Lc);
pa = La->next;
pb = (*Lb)->next;
while(pa && pb)
{
i++;
if(i%2)
{
cur->next = pa;
cur = pa;
pa = pa->next;
}
else
{
cur->next = pb;
cur = pb;
pb = pb->next;
}
}
if(!pa) //La先扫描完
cur->next = pb;
if(!pb) //Lb先扫描完注意与方法一的区别
cur->next = pa;
free((*Lb));
*Lb = NULL;
return OK;
}
void PrintElem(LElemType_L e)
{
printf("%d ", e);
printf("%2d ", e);
}

View File

@@ -3,18 +3,20 @@
#include "LinkList.h" //**▲02 线性表**//
/*
* 题2.23——方法一将La插入到Lb中
* 题2.23
*
* 合并两个单链表。
* 合并完成后将La和Lb置空但不销毁。
* 方法一将La中的元素插入到Lb中然后让Lc指向Lb
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc);
/*
* 题2.23——方法二将La和Lb中的元素交替插入到Lc中
* 题2.23
*
* 合并两个单链表。
* 合并完成后将La和Lb置空但不销毁。
* 方法二将La和Lb中的元素交替摘下并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc);
@@ -26,19 +28,25 @@ int main(int argc, char* argv[]) {
LinkList La, Lb, Lc;
int i;
// 0号单元存储的是数组长度
int a[] = {10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
int b[] = {8, 2, 4, 6, 8, 10, 12, 14, 16};
// 准备测试数据
InitList(&La);
InitList(&Lb);
for(i = 1; i <= 5; i++) {
ListInsert(La, i, 2 * i - 1);
ListInsert(Lb, i, 2 * i);
for(i = 1; i <= a[0]; i++) {
ListInsert(La, i, a[i]);
}
for(i = 1; i <= b[0]; i++) {
ListInsert(Lb, i, b[i]);
}
printf("La = ");
ListTraverse(La, PrintElem);
printf("Lb = ");
ListTraverse(Lb, PrintElem);
// 并方法测试
// 并方法测试
// Algo_2_23_1(La, Lb, &Lc);
Algo_2_23_2(La, Lb, &Lc);
@@ -49,10 +57,19 @@ int main(int argc, char* argv[]) {
}
// 合并两个单链表
/*
* 题2.23
*
* 方法一将La中的元素插入到Lb中然后让Lc指向Lb
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc) {
LinkList p, pb;
// 初始化Lc
InitList(Lc);
// 确保La和Lb存在
if(La == NULL || Lb == NULL || Lc == NULL) {
return ERROR;
@@ -60,6 +77,7 @@ Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc) {
pb = Lb;
// 先遍历La和Lb的共同部分
while(La->next != NULL && pb->next != NULL) {
// 从La中摘下结点
p = La->next;
@@ -73,66 +91,74 @@ Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc) {
pb = pb->next->next;
}
// 如果La有剩余需要将其全部链接到Lb的尾部
// 如果La有剩余但Lb已遍历到尽头则需要将La中剩余元素整体链接到Lb的尾部
if(pb->next == NULL && La->next != NULL) {
pb->next = La->next;
La->next = NULL;
}
InitList(Lc);
// 让Lc指向Lb的链表
(*Lc)->next = Lb->next;
Lb->next = NULL;
return OK;
}
// 合并两个单链表
/*
* 题2.23
*
* 方法二将La和Lb中的元素交替摘下并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc) {
LinkList p, pc;
int flag; // 指挥插入La中的元素还是插入Lb中的元素
int flag; // 指挥当前应当摘下La中的元素还是摘下Lb中的元素
// 初始化Lc
InitList(Lc);
// 确保La和Lb存在
if(La == NULL || Lb == NULL || Lc == NULL) {
return ERROR;
}
InitList(Lc);
flag = 0;
pc = *Lc;
while(La->next!=NULL && Lb->next!=NULL){
// 需要插入La中的元素
if(flag==0) {
// 先遍历La和Lb的共同部分
while(La->next != NULL && Lb->next != NULL) {
// 摘下La中的元素
if(flag == 0) {
// 摘下La中的元素
p = La->next;
La->next = p->next;
flag = 1;
} else {
// 摘下La中的元素
} else {
p = Lb->next;
Lb->next = p->next;
flag = 0;
}
// 将摘下的元素插入到Lc
pc->next = p;
pc = pc->next;
}
// 如果Lb可能有剩余
if(La->next==NULL) {
// 摘下Lb中元素
// 如果La已经遍历到尽头(Lb可能有剩余)
if(La->next == NULL) {
// 摘下Lb中可能剩余的所有元素
p = Lb->next;
Lb->next = NULL;
pc->next = p;
// 如果La有剩余
// 如果La有剩余(Lb一定遍历到尽头了否则上面的while循环会继续执行)
} else {
// 摘下La中的元素
// 摘下La中剩余的元素
p = La->next;
La->next = NULL;
pc->next = p;
@@ -143,5 +169,5 @@ Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc) {
// 测试函数,打印元素
void PrintElem(ElemType e) {
printf("%d ", e);
printf("%2d ", e);
}

View File

@@ -3,18 +3,20 @@
#include "LinkList.h" //**▲02 线性表**//
/*
* 题2.23——方法一将La插入到Lb中
* 题2.23
*
* 合并两个单链表。
* 合并完成后将La和Lb置空但不销毁。
* 方法一将La中的元素插入到Lb中然后让Lc指向Lb
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc);
/*
* 题2.23——方法二将La和Lb中的元素交替插入到Lc中
* 题2.23
*
* 合并两个单链表。
* 合并完成后将La和Lb置空但不销毁。
* 方法二将La和Lb中的元素交替摘下并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc);
@@ -25,123 +27,148 @@ void PrintElem(ElemType e);
int main(int argc, char* argv[]) {
LinkList La, Lb, Lc;
int i;
// 0号单元存储的是数组长度
int a[] = {10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
int b[] = { 8, 2, 4, 6, 8, 10, 12, 14, 16};
// 准备测试数据
InitList(&La);
InitList(&Lb);
for(i = 1; i <= 5; i++) {
ListInsert(La, i, 2 * i - 1);
ListInsert(Lb, i, 2 * i);
for(i = 1; i <= a[0]; i++) {
ListInsert(La, i, a[i]);
}
for(i = 1; i <= b[0]; i++) {
ListInsert(Lb, i, b[i]);
}
printf("La = ");
ListTraverse(La, PrintElem);
printf("Lb = ");
ListTraverse(Lb, PrintElem);
// 并方法测试
// 并方法测试
// Algo_2_23_1(La, Lb, &Lc);
Algo_2_23_2(La, Lb, &Lc);
printf("Lc = ");
ListTraverse(Lc, PrintElem);
return 0;
}
// 合并两个单链表
/*
* 题2.23
*
* 方法一将La中的元素插入到Lb中然后让Lc指向Lb
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc) {
LinkList p, pb;
// 初始化Lc
InitList(Lc);
// 确保La和Lb存在
if(La == NULL || Lb == NULL || Lc == NULL) {
return ERROR;
}
pb = Lb;
// 先遍历La和Lb的共同部分
while(La->next != NULL && pb->next != NULL) {
// 从La中摘下结点
p = La->next;
La->next = p->next;
// 将La中摘下的结点插入到Lb中
p->next = pb->next;
pb->next = p;
// 前进到原Lb中下一个结点的位置
pb = pb->next->next;
}
// 如果La有剩余需要将其全部链接到Lb的尾部
// 如果La有剩余但Lb已遍历到尽头则需要将La中剩余元素整体链接到Lb的尾部
if(pb->next == NULL && La->next != NULL) {
pb->next = La->next;
La->next = NULL;
}
InitList(Lc);
// 让Lc指向Lb的链表
(*Lc)->next = Lb->next;
Lb->next = NULL;
return OK;
}
// 合并两个单链表
/*
* 题2.23
*
* 方法二将La和Lb中的元素交替摘下并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc) {
LinkList p, pc;
int flag; // 指挥插入La中的元素还是插入Lb中的元素
int flag; // 指挥当前应当摘下La中的元素还是摘下Lb中的元素
// 初始化Lc
InitList(Lc);
// 确保La和Lb存在
if(La == NULL || Lb == NULL || Lc == NULL) {
return ERROR;
}
InitList(Lc);
flag = 0;
pc = *Lc;
// 先遍历La和Lb的共同部分
while(La->next!=NULL && Lb->next!=NULL){
// 需要插入La中的元素
// 摘下La中的元素
if(flag==0) {
// 摘下La中的元素
p = La->next;
La->next = p->next;
flag = 1;
} else {
// 摘下La中的元素
} else {
p = Lb->next;
Lb->next = p->next;
flag = 0;
}
// 将摘下的元素插入到Lc
pc->next = p;
pc = pc->next;
}
// 如果Lb可能有剩余
// 如果La已经遍历到尽头(Lb可能有剩余)
if(La->next==NULL) {
// 摘下Lb中元素
// 摘下Lb中可能剩余的所有元素
p = Lb->next;
Lb->next = NULL;
pc->next = p;
// 如果La有剩余
// 如果La有剩余(Lb一定遍历到尽头了否则上面的while循环会继续执行)
} else {
// 摘下La中的元素
// 摘下La中剩余的元素
p = La->next;
La->next = NULL;
pc->next = p;
}
return OK;
}
// 测试函数,打印元素
void PrintElem(ElemType e) {
printf("%d ", e);
printf("%2d ", e);
}

View File

@@ -3,18 +3,20 @@
#include "LinkList.h" //**▲02 线性表**//
/*
* 题2.23——方法一将La插入到Lb中
* 题2.23
*
* 合并两个单链表。
* 合并完成后将La和Lb置空但不销毁。
* 方法一将La中的元素插入到Lb中然后让Lc指向Lb
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc);
/*
* 题2.23——方法二将La和Lb中的元素交替插入到Lc中
* 题2.23
*
* 合并两个单链表。
* 合并完成后将La和Lb置空但不销毁。
* 方法二将La和Lb中的元素交替摘下并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc);
@@ -26,19 +28,25 @@ int main(int argc, char* argv[]) {
LinkList La, Lb, Lc;
int i;
// 0号单元存储的是数组长度
int a[] = {10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
int b[] = { 8, 2, 4, 6, 8, 10, 12, 14, 16};
// 准备测试数据
InitList(&La);
InitList(&Lb);
for(i = 1; i <= 5; i++) {
ListInsert(La, i, 2 * i - 1);
ListInsert(Lb, i, 2 * i);
for(i = 1; i <= a[0]; i++) {
ListInsert(La, i, a[i]);
}
for(i = 1; i <= b[0]; i++) {
ListInsert(Lb, i, b[i]);
}
printf("La = ");
ListTraverse(La, PrintElem);
printf("Lb = ");
ListTraverse(Lb, PrintElem);
// 并方法测试
// 并方法测试
// Algo_2_23_1(La, Lb, &Lc);
Algo_2_23_2(La, Lb, &Lc);
@@ -49,10 +57,19 @@ int main(int argc, char* argv[]) {
}
// 合并两个单链表
/*
* 题2.23
*
* 方法一将La中的元素插入到Lb中然后让Lc指向Lb
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc) {
LinkList p, pb;
// 初始化Lc
InitList(Lc);
// 确保La和Lb存在
if(La == NULL || Lb == NULL || Lc == NULL) {
return ERROR;
@@ -60,6 +77,7 @@ Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc) {
pb = Lb;
// 先遍历La和Lb的共同部分
while(La->next != NULL && pb->next != NULL) {
// 从La中摘下结点
p = La->next;
@@ -73,45 +91,53 @@ Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc) {
pb = pb->next->next;
}
// 如果La有剩余需要将其全部链接到Lb的尾部
// 如果La有剩余但Lb已遍历到尽头则需要将La中剩余元素整体链接到Lb的尾部
if(pb->next == NULL && La->next != NULL) {
pb->next = La->next;
La->next = NULL;
}
InitList(Lc);
// 让Lc指向Lb的链表
(*Lc)->next = Lb->next;
Lb->next = NULL;
return OK;
}
// 合并两个单链表
/*
* 题2.23
*
* 方法二将La和Lb中的元素交替摘下并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc) {
LinkList p, pc;
int flag; // 指挥插入La中的元素还是插入Lb中的元素
int flag; // 指挥当前应当摘下La中的元素还是摘下Lb中的元素
// 初始化Lc
InitList(Lc);
// 确保La和Lb存在
if(La == NULL || Lb == NULL || Lc == NULL) {
return ERROR;
}
InitList(Lc);
flag = 0;
pc = *Lc;
// 先遍历La和Lb的共同部分
while(La->next!=NULL && Lb->next!=NULL){
// 需要插入La中的元素
// 摘下La中的元素
if(flag==0) {
// 摘下La中的元素
p = La->next;
La->next = p->next;
flag = 1;
} else {
// 摘下La中的元素
} else {
p = Lb->next;
Lb->next = p->next;
@@ -123,16 +149,16 @@ Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc) {
pc = pc->next;
}
// 如果Lb可能有剩余
// 如果La已经遍历到尽头(Lb可能有剩余)
if(La->next==NULL) {
// 摘下Lb中元素
// 摘下Lb中可能剩余的所有元素
p = Lb->next;
Lb->next = NULL;
pc->next = p;
// 如果La有剩余
// 如果La有剩余(Lb一定遍历到尽头了否则上面的while循环会继续执行)
} else {
// 摘下La中的元素
// 摘下La中剩余的元素
p = La->next;
La->next = NULL;
pc->next = p;
@@ -143,5 +169,5 @@ Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc) {
// 测试函数,打印元素
void PrintElem(ElemType e) {
printf("%d ", e);
printf("%2d ", e);
}