Skip to content

Commit

Permalink
♻️ 更新习题2.23的注释,顺便将CFree的代码更新为与其他分支一致
Browse files Browse the repository at this point in the history
  • Loading branch information
kangjianwei committed Mar 25, 2020
1 parent 9bf5d0d commit 0efbc2b
Show file tree
Hide file tree
Showing 4 changed files with 349 additions and 224 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);

void PrintElem(LElemType_L e);
//测试函数,打印整型

int main(int argc, char *argv[])
{
LinkList La, Lb, Lc;
int i, mark;

if(InitList_L(&La) && InitList_L(&Lb) && InitList_L(&Lc)) //链表L创建成功
{
for(i=1; i<=5; i++) //创建链表La和Lb
{
ListInsert_L(La, i, 2*i-1);
ListInsert_L(Lb, i, 2*i);
}
}
/*
* 题2.23
*
* 方法一:将La中的元素插入到Lb中,然后让Lc指向Lb
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_1(LinkList La, LinkList Lb, LinkList* Lc);

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");
/*
* 题2.23
*
* 方法二:将La和Lb中的元素交替摘下,并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
Status Algo_2_23_2(LinkList La, LinkList Lb, LinkList* Lc);

if(mark==1)
{
printf("题 2.23 方法1 验证...\n");
Algo_2_23_1(La, &Lb, &Lc);
}
// 测试函数,打印元素
void PrintElem(LElemType_L e);

if(mark==2)
{
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;
}

/*━━━━━━━━━━━┓
┃题2.23:归并两个单链表┃
┗━━━━━━━━━━━*/
/* 方法一:顺序链接 */
Status Algo_2_23_1(LinkList La, LinkList *Lb, LinkList *Lc)
int main(int argc, char* argv[])
{
LinkList prea, pa, pb;
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;
}

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)
/*
* 题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)
{
(*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;
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:归并两个单链表┃
┗━━━━━━━━━━━*/
/* 方法二:交替链接 */
Status Algo_2_23_2(LinkList La, LinkList *Lb, LinkList *Lc)
/*
* 题2.23
*
* 方法二:将La和Lb中的元素交替摘下,并将其插入到Lc中
*
* 交错归并两个单链表,新链表使用原链表的存储空间。
*/
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)
LinkList p, pc;
int flag; // 指挥当前应当摘下La中的元素还是摘下Lb中的元素

// 初始化Lc
InitList_L(Lc);

// 确保La和Lb存在
if(La == NULL || Lb == NULL || Lc == NULL)
{
i++;
if(i%2)
{
cur->next = pa;
cur = pa;
pa = pa->next;
}
else
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
{
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;
p = Lb->next;
Lb->next = p->next;

flag = 0;
}

// 将摘下的元素插入到Lc
pc->next = p;
pc = pc->next;
}

// 如果La已经遍历到尽头(Lb可能有剩余)
if(La->next==NULL)
{
// 摘下Lb中可能剩余的所有元素
p = Lb->next;
Lb->next = NULL;
pc->next = p;
}
// 如果La有剩余(Lb一定遍历到尽头了,否则上面的while循环会继续执行)
else
{
// 摘下La中剩余的元素
p = La->next;
La->next = NULL;
pc->next = p;
}

return OK;
}

void PrintElem(LElemType_L e)
// 测试函数,打印元素
void PrintElem(LElemType_L e)
{
printf("%d ", e);
printf("%2d ", e);
}
Loading

0 comments on commit 0efbc2b

Please sign in to comment.