PA0:关于剩余练习2

32、

双向链表在多数时候都优于单向链表,双向链表意味着它可以方便地访问自己的前驱节点和后继节点,代价只是多占用一点空间给指针。此外,作者也对应配了头指针和尾指针,在作者的例子里还有pop和push,那双指针就显得很重要了,单链表配单指针,会让pop和push变得更耗时间。

 

先看头文件部分

#define List_count(A) ((A)->count)

#define List_first(A) ((A)->first != NULL ? (A)->first->value : NULL)

#define List_last(A) ((A)->last != NULL ? (A)->last->value : NULL)    这个写法值得学习一下,在前面已经对结构体进行了定义,这里的宏就是直接把 链表元素数、首个元素值和最后元素值包装了起来。之后用前面的形式,看起来更加直观。

除此之外,后面还有一段宏,

#define LIST_FOREACH(L, S, M, V) ListNode *_node = NULL;\

    ListNode *V = NULL;\

    for(V = _node = L->S; _node != NULL; V = _node = _node->M)

  说实话以前没见过这种写法。在后面函数里,需要多次写循环体,作者在这里就用一个宏来替代后面的循环,要循环的时候直接list_foreach就行。在前两行代码的后面有斜杠,表示代码还没写完,后面还是代码。这段代码的用法就是直接在后文里需要用循环体的地方直接替换,充当循环。for循环条件里面的连等是同时对前面的所有变量赋相同的值,比如给V和_node同时赋值L-->S.

  关于循环里面的字母,L代表头指针,存储链表头结点地址;S是头结点里指向第一个节点的指针的名字,M是节点里指向下个节点的指针的名字,V是用来储存当前正在遍历节点的指针变量。 C语言里并没有规定字母必须是什么意思,这里只是我们人为地赋予了这个含义。需要注意的是,编译器不会检查到底输入了什么,所以字母对应位置输入别的也行,但是会报错。

  在实际代码中也可以看到这段宏的效果:

 LIST_FOREACH(list, first, next, cur) {
        if(cur->prev) {
            free(cur->prev);
        }
    }

就这样遍历释放掉了链表。

 

再看代码部分,

calloc(num,size)   连续分配num个size的连续空间   之后就是链表相关函数的具体代码。

void List_destroy(List *list)
{
    LIST_FOREACH(list, first, next, cur) {
        if(cur->prev) {
            free(cur->prev);
        }
    }

    free(list->last);
    free(list);
}  //逐个检查有没有前驱节点,有就销毁,最后再单独处理掉尾节点

 

关于单元测试这一块,项目没有要求,所以中间的就先跳过了,之后有空闲的时候再抽需要的回看。从代码上看,就是使用断言功能,对每一项函数进行功能测试。注意断言需要-g,没有debug项的话,断言功能会被自动忽略。 

尝试学习代码,对count计数进行检测:

char *test_count()
{
    // 测试count功能  假设一开始L链表内为空
    List_unshift(list, test1); //快速向头部增加元素
    mu_assert(count == 1, " Wrong count after operation ");

    List_unshift(list, test2);
    mu_assert(count == 2, " Wrong count after operation ");

    List_unshift(list, test3);
    mu_assert(count == 3, " Wrong count after operation ");

    count=-count;
    mu_assert(count == -3, “Wrong count after operation”);
    return NULL;
}

 

------------练习33----

链表冒泡相对来说比较好做,链表归并,说实话归并排序我平时没有用过,只是知道原理,要用起来还是第一次:

int List_bubble_sort(List *list,List_compare cmp)
{
    int length=List_count(list);
    if(length<=1) 
    {
        die("too few");
    } //只有一个元素,那也报错,没有必要排序
    //不过有必要考虑<0吗?因为count不应该出现小于0的情况 
    int i,j;
    ListNode *cur=list->next;   //我的代码没有用foreach宏,所以要单独定义 
    for(i=0;i<length;i++)
    {
        for(j=0;j<length-1;j++)
        {
            if(cmp(cur->value,cur->next->value)>0)//用cmp,这样之后方便换升降序 
            {
                ListNode_swap(cur,cur->next); //交换节点内容 
                cur=cur->next; //指针前进 
            }
        }
        cur=list->next;//走完一轮,cur指针要回到首位 
    } 
    
}  //链表冒泡排序 

 

 

值得一提的是,我看了作者给出的样例代码,按照这种写法,似乎冒泡只执行了一层,但冒泡应该是有两层循环才有效果。不知道是不是哪里看漏了。

链表这种逻辑结构,相比于数组,并不适合用于排序和读写,因为数组在逻辑上是连续的,支持随机读写,但链表不行,不管是只有头指针还是首尾指针都有,都没办法做到随机存取。进行排序时要自己维护链表,所以就显得十分麻烦。

单元测试:

 

#include <time.h>


int test[13]={13,43241,3,1243,556,9,3424,332,1443,2,1132144,35,11};
int *a1=&test[0];
int *a2=&test[1];
int *a3=&test[2];
int *a4=&test[3];
int *a5=&test[4];
int *a6=&test[5];
int *a7=&test[6];
int *a8=&test[7];
int *a9=&test[8];
int *a10=&test[9];
int *a11=&test[10];
int *a12=&test[11];
int *a13=&test[12];

void List_init(List *list)
{
    List_unshift(list,a1);
    List_unshift(list,a2);
    List_unshift(list,a3);
    List_unshift(list,a4);
    List_unshift(list,a5);
    List_unshift(list,a6);
    List_unshift(list,a7);
    List_unshift(list,a8);
    List_unshift(list,a9);
    List_unshift(list,a10);
    List_unshift(list,a11);
    List_unshift(list,a12);
    List_unshift(list,a13);
} 

char * test()
{
    List *list;
    time_t bubble_start,bubble_end,merge_start,merge_end;
    
    List_init(list);    
    bubble_start=time(NULL);
    List_bubble_sort(list,(List_compare)strcmp);
    bubble_end=time(NULL);
    printf("冒泡排序的用时:%s\n",difftime(bubble_end,bubble_start));
    List_destory(list);
    
    List *list;
    List_init(list);
    merge_start=time(NULL);
    List_merge_sort(list,(List_compare)strcmp);
    merge_end=time(NULL);
    printf("归并排序的用时:%s\n",difftime(merge_end,merge_start));
    List_clear_destory(list);
}

 

posted @ 2024-01-19 15:43  namezhyp  阅读(16)  评论(0编辑  收藏  举报