Skip to content

Commit

Permalink
🐛 (kangjianwei#17)修复习题2.28没有释放无效结点的bug,顺便将CFree的代码更新为与其他分支一致
Browse files Browse the repository at this point in the history
  • Loading branch information
kangjianwei committed Mar 25, 2020
1 parent 9170a53 commit 6449fae
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 230 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,144 +2,121 @@
#include "../../../▲课本算法实现/▲01 绪论/Status.h" //**▲01 绪论**//
#include "../../../▲课本算法实现/▲02 线性表/04 SinglyLinkedList/SinglyLinkedList.c" //**▲02 线性表**//

/* 函数原型 */
Status Algo_2_28__1(LinkList La, LinkList Lb, LinkList Lc);
Status Algo_2_28__2(LinkList La, LinkList Lb);

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

int main(int argc, char *argv[])
{
LinkList La, Lb, Lc_1, *Lc_2;
int i;
int a[10] = {1,2,2,3,4,5,6,7,7,8};
int b[10] = {2,2,3,4,4,6,7,8,8,9};

if(InitList_L(&La) && InitList_L(&Lb)) //链表创建成功
{
for(i=1; i<=10; i++) //链表赋值
{
ListInsert_L(La, i, a[i-1]);
ListInsert_L(Lb, i, b[i-1]);
}
}

printf("La = ");
ListTraverse_L(La, PrintElem); //输出
printf("\n");
printf("Lb = ");
ListTraverse_L(Lb, PrintElem);
printf("\n\n");

printf("题 2.28 第(1)问验证:\n");
InitList_L(&Lc_1);
Algo_2_28__1(La, Lb, Lc_1);
printf("Lc = La∩Lb = ");
ListTraverse_L(Lc_1, PrintElem); //输出L
printf("\n\n");
/*
* 题2.28
*
* 求交集:C=A∩B。
*
* A和B中元素可能重复,但C中元素不重复。
* 而且,要求C利用A原有的空间,但是A中的无效结点会被释放。
*/
Status Algo_2_28(LinkList La, LinkList Lb, LinkList* Lc);

printf("题 2.28 第(2)问验证:\n");
Algo_2_28__2(La, Lb);
Lc_2 = &La;
printf("Lc = La∩Lb = ");
ListTraverse_L(*Lc_2, PrintElem); //输出L
printf("\n\n");

return 0;
}
// 测试函数,打印元素
void PrintElem(LElemType_L e);

/*━━━━━━━┓
┃题2.28:C=A∩B┃
┗━━━━━━━*/
/* (1) */
Status Algo_2_28__1(LinkList La, LinkList Lb, LinkList Lc)
{
LinkList pa, pb, pc, s;

if(!La || !Lb)
return ERROR;

pa = La->next;
pb = Lb->next;
pc = Lc;

while(pa && pb)
{
if(pa->data==pb->data)
{
if(pc==Lc || pc->data!=pa->data)
{
s = (LinkList)malloc(sizeof(LNode));
if(!s)
exit(OVERFLOW);
s->data = pa->data;
s->next = NULL;

pc->next = s;
pc = pc->next;
}

pa = pa->next;
pb = pb->next;
}
else if(pa->data<pb->data)
pa = pa->next;
else
pb = pb->next;
}

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

// 0号单元存储的是数组长度
int a[] = {10, 1, 1, 1, 7, 7, 9, 10, 18, 18, 19};
int b[] = {8, 1, 1, 7, 7, 7, 15, 18, 18};

// 准备测试数据,同一表中的元素值可能相同
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_28(La, Lb, &Lc);

printf("Lc = ");
ListTraverse_L(Lc, PrintElem);
printf("\n");

return 0;
}

/*━━━━━━━┓
┃题2.28:C=A∩B┃
┗━━━━━━━*/
/* (2) */
Status Algo_2_28__2(LinkList La, LinkList Lb)
{
LinkList pa, pb, p;

if(!La || !Lb)
return ERROR;

pa = La->next;
pb = Lb->next;
p = La;

while(pa && pb)
{
if(pa->data==pb->data)
{
if(p==La || p->data!=pa->data)
{
p->next = pa;
p = pa;
pa = pa->next;
}
else
{
p->next = pa->next;
free(pa);
pa = p->next;
}
/*
* 题2.28
*
* 求交集:C=A∩B。
*
* A和B中元素可能重复,但C中元素不重复。
* 而且,要求C利用A原有的空间,但是A中的无效结点会被释放。
*/
Status Algo_2_28(LinkList La, LinkList Lb, LinkList* Lc) {
LinkList pa, pb, pc, s;

// 确保La和Lb存在
if(La == NULL || Lb == NULL) {
return ERROR;
}

// Lc利用La的空间
*Lc = La;

pa = La->next;
pb = Lb->next;
pc = *Lc;

// 遍历La和Lb的共同部分
while(pa != NULL && pb != NULL) {
if(pa->data < pb->data) {
pc->next = pa->next;
free(pa); // 释放La中的无效结点
pa = pc->next;
} else if(pa->data > pb->data) {
pb = pb->next;

// 遇到交集元素
} else {
// 如果Lc不为空,则需要确保Lc中的元素不重复
if(pc == (*Lc) || pc->data != pa->data) {
pc = pc->next; // pc游标直接前进,相当于保留了pa指向的元素

pa = pa->next;
} else {
// 如果该交集元素已经存在了,则释放这个结点
pc->next = pa->next;
free(pa); // 释放La中的无效结点

pa = pc->next;
}

// pb总是照常前进
pb = pb->next;
}
}

// Lc已生成,Lc和La共享一段内存
pc->next = NULL;

pb = pb->next;
}
else if(pa->data<pb->data)
{
p->next = pa->next;
free(pa);
pa = p->next;
}
else
pb = pb->next;
}

return OK;
// 释放La中多余的无效结点
while(pa!=NULL){
s = pa;
pa = pa->next;
free(s);
}

return OK;
}

void PrintElem(LElemType_L e)
{
printf("%d ", e);
// 测试函数,打印元素
void PrintElem(LElemType_L e) {
printf("%2d ", e);
}
92 changes: 59 additions & 33 deletions CLion/ExerciseBook/02.28/02.28.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
* 题2.28
*
* 求交集:C=A∩B。
* 不允许C中的元素重复,且C会利用A原有的空间,A被销毁。
*
* A和B中元素可能重复,但C中元素不重复。
* 而且,要求C利用A原有的空间,但是A中的无效结点会被释放。
*/
LinkList Algo_2_28(LinkList* La, LinkList Lb);
Status Algo_2_28(LinkList La, LinkList Lb, LinkList* Lc);

// 测试函数,打印元素
void PrintElem(ElemType e);
Expand All @@ -17,23 +19,26 @@ int main(int argc, char* argv[]) {
LinkList La, Lb, Lc;
int i;

int a[10] = {1, 2, 2, 3, 4, 4, 9, 9, 10, 12};
int b[10] = {1, 1, 2, 2, 3, 3, 4, 5, 12, 13};
// 0号单元存储的是数组长度
int a[] = {10, 1, 1, 1, 7, 7, 9, 10, 18, 18, 19};
int b[] = {8, 1, 1, 7, 7, 7, 15, 18, 18};

// 准备测试数据
// 准备测试数据,同一表中的元素值可能相同
InitList(&La);
InitList(&Lb);
for(i = 1; i <= 10; i++) {
ListInsert(La, i, a[i - 1]);
ListInsert(Lb, i, b[i - 1]);
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);

// 求交集
Lc = Algo_2_28(&La, Lb);
Algo_2_28(La, Lb, &Lc);

printf("Lc = ");
ListTraverse(Lc, PrintElem);
Expand All @@ -42,51 +47,72 @@ int main(int argc, char* argv[]) {
}


LinkList Algo_2_28(LinkList* La, LinkList Lb) {
LinkList Lc;
/*
* 题2.28
*
* 求交集:C=A∩B。
*
* A和B中元素可能重复,但C中元素不重复。
* 而且,要求C利用A原有的空间,但是A中的无效结点会被释放。
*/
Status Algo_2_28(LinkList La, LinkList Lb, LinkList* Lc) {
LinkList pa, pb, pc, s;

// 确保La和Lb存在
if(La == NULL || *La == NULL || Lb == NULL) {
return NULL;
if(La == NULL || Lb == NULL) {
return ERROR;
}

pa = (*La)->next;
pb = Lb->next;
// Lc利用La的空间
*Lc = La;

Lc = *La;
Lc->next = NULL;
pc = Lc;
pa = La->next;
pb = Lb->next;
pc = *Lc;

// 只遍历La和Lb的共同部分就行
// 遍历La和Lb的共同部分
while(pa != NULL && pb != NULL) {
if(pa->data < pb->data) {
s = pa;
pa = pa->next;
free(s);
pc->next = pa->next;
free(pa); // 释放La中的无效结点
pa = pc->next;
} else if(pa->data > pb->data) {
pb = pb->next;

// 遇到交集元素
} else {
// 确保Lc中的元素不重复
if(pc == Lc || pc->data != pa->data) {
pc->next = pa;
pc = pc->next;
// 如果Lc不为空,则需要确保Lc中的元素不重复
if(pc == (*Lc) || pc->data != pa->data) {
pc = pc->next; // pc游标直接前进,相当于保留了pa指向的元素

pa = pa->next;
} else {
// 如果该交集元素已经存在了,则释放这个结点
pc->next = pa->next;
free(pa); // 释放La中的无效结点

pa = pc->next;
}
pa = pa->next;

// pb总是照常前进
pb = pb->next;
}
}

// Lc已生成,Lc和La共享一段内存
pc->next = NULL;

// 释放La中多余的无效结点
while(pa!=NULL){
s = pa;
pa = pa->next;
free(s);
}


*La = NULL;

return Lc;
return OK;
}

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

0 comments on commit 6449fae

Please sign in to comment.