第二十三天(数据结构,有节点的双向链表)常用练习

#include "ListWithHead.h"




//创建头节点

LWH_HeadNode * LWH_HeadNode_Create(void)

{

    //直接将我们的头节点在堆上面创建  然后将其返回  用的事calloc自动初始化为0

    return (LWH_HeadNode *)calloc(1,sizeof(LWH_HeadNode));

}



//创建双向链表的节点 基于数据

static LWH_Node *LWH_Node_Create(const LWH_DataType data)

{

    LWH_Node * ptr = (LWH_Node *)calloc(1,sizeof(LWH_Node));

    ptr ->_data = data;

    return ptr;

}



//将节点插入到链表里面去  尾查

static void LWH_Node_Insertback(LWH_HeadNode * head,LWH_Node * node)

{

    if(!head || !node)

        return;

    //什么时候需要动first  链表不存在就要动了

    if(!head ->_first)

    {

        //你加入的节点就是第一个 也是最后一个

        head ->_first = head ->_last = node;

    }

    else//链表存在了

    {

        head ->_last ->_next = node;//将这个节点接在最后一个的后面

        node ->_prev = head ->_last;//这个节点的前面变成刚刚的最后一个节点

        head ->_last = node;//最后一个换到node上面去

    }

    head ->_num++;

}



//将节点插入到链表里面去 头插

static void LWH_Node_Insertfront(LWH_HeadNode * head,LWH_Node * node)

{

    if(!head || !node)

        return;

    if(!head ->_first)

    {

        //你加入的节点就是第一个 也是最后一个

        head ->_first = head ->_last = node;

    }

    else//链表存在了

    {

        head ->_first ->_prev = node;//第一个节点的前面变成了node

        node ->_next = head ->_first;//node的后面变成了现在的链表的第一个

        head ->_first = node;//将链表的第一个转到node上面去

    }

    head ->_num++;

}




//将数据插入到链表里面去

void LWH_Push_Back(LWH_HeadNode * head,const LWH_DataType data)

{

    LWH_Node_Insertback(head,LWH_Node_Create(data));

}

//push_front    头插                作业

void LWH_Push_Front(LWH_HeadNode * head,const LWH_DataType data)

{

    LWH_Node_Insertfront(head,LWH_Node_Create(data));

}





//获取长度

int LWH_Length(LWH_HeadNode * head)

{

    if(LWH_Empty(head))

        return 0;

    return head ->_num;

}



//做遍历指针 第一个(begin)  最后一个(rbegin) 结束(end)  下一个(next)  上一个prev 获取数据getdata

void LWH_Begin(LWH_HeadNode * head)

{

    if(!head)

        return;

    head ->_ptr = head ->_first;

}

void LWH_Rbegin(LWH_HeadNode * head)

{

    if(!head)

        return;

    head ->_ptr = head ->_last;

}

bool LWH_End(LWH_HeadNode * head)

{

    if(!head)

        return true;

    return head ->_ptr == NULL;

}

void LWH_Next(LWH_HeadNode * head)

{

    if(!LWH_End(head))

        head ->_ptr = head ->_ptr ->_next;

}

void LWH_Prev(LWH_HeadNode * head)

{

    if(!LWH_End(head))

        head ->_ptr = head ->_ptr ->_prev;

}

LWH_DataType LWH_GetData(LWH_HeadNode * head)

{

    if(!LWH_End(head))

        return head ->_ptr ->_data;

    return LWH_ERRORVALUE;

}




//判断这个链表是不是空的

bool LWH_Empty(LWH_HeadNode * head)

{

    if(!head)

        return true;

    return head ->_num == 0;

}




//删除第一个(如果ptr正好在这里,我们需要指向下一个) 返回删除节点的数据,返回LWH_ERRORVALUE为错误

//删除最后一个(如果ptr正好在这里,我们需要指向上一个) 返回删除节点的数据,返回LWH_ERRORVALUE为错误

LWH_DataType LWH_Pop_Front(LWH_HeadNode * head)

{

    if(!head || LWH_Empty(head))

        return LWH_ERRORVALUE;

    LWH_Node * ptr = head ->_first;//标记你要删除的节点

    //如果ptr正好在这里,我们需要指向下一个

    if(head ->_ptr == ptr)

        head ->_ptr = ptr ->_next;

    if(head ->_first != head ->_last)

    {

        //缩头  将新的头的前面一个删除

        head ->_first = head ->_first ->_next;

        head ->_first ->_prev = NULL;

        //孤立ptr

        ptr ->_next = NULL;        

    }

    else//就这有这么一个 你还要删了

    {

        head ->_first = head ->_last = NULL;//将头和尾都指向NULL  一个元素都没有了    

    }

    LWH_DataType data = ptr ->_data;

    free(ptr);

    head ->_num--;

    return data;

}



LWH_DataType LWH_Pop_Back(LWH_HeadNode * head)

{

    if(!head || LWH_Empty(head))

        return LWH_ERRORVALUE;

    LWH_Node * ptr = head ->_last;//标记你要删除的节点

    //如果ptr正好在这里,我们需要指向上一个

    if(head ->_ptr == ptr)

        head ->_ptr = ptr ->_prev;

    if(head ->_first != head ->_last)

    {

        //缩尾  将新的尾的后面一个删除

        head ->_last = head ->_last ->_prev;

        head ->_last ->_next = NULL;

        //孤立ptr

        ptr ->_prev = NULL;        

    }

    else//就这有这么一个 你还要删了

    {

        head ->_first = head ->_last = NULL;//将头和尾都指向NULL  一个元素都没有了    

    }

    LWH_DataType data = ptr ->_data;

    free(ptr);

    head ->_num--;

    return data;

}

//清空

void LWH_Clear(LWH_HeadNode * head,void (*callback)(const LWH_DataType))

{

    if(!head)

        return;

    while(!LWH_Empty(head))

    {

        LWH_DataType data = LWH_Pop_Back(head);

        if(callback)

        {

            callback(data);

        }

    }

}



//销毁这个链表 弄完那边的head会指向NULL

void LWH_Destory(LWH_HeadNode ** head,void (*callback)(const LWH_DataType))

{

    if(!head)

        return;

    LWH_Clear(* head,callback);



    free(*head);

    *head = NULL;

}




//Remove_if     删除按照规则返回true(从开始到结尾,找到的第一个删除)

//你们可以继续扩充到 Remove_if_all  将所有满足条件的删除

//返回该元素 返回LWH_ERRORVALUE为删除失败

LWH_DataType LWH_Remove_if(LWH_HeadNode * head,bool (*callback)(const LWH_DataType))

{

    if(!head || !callback)

        return LWH_ERRORVALUE;

    //你需要一个遍历指针来找

    LWH_Node * ptr = head ->_first;

    while(ptr)

    {

        if(callback(ptr ->_data))//为真就要删除

        {

            LWH_DataType data = ptr ->_data;

            if(ptr == head ->_first)//ptr可能是头

            {

                LWH_Pop_Front(head);    

            }

            else if(ptr == head ->_last)//ptr可能是尾

            {

                LWH_Pop_Back(head);    

            }

            else//删中间

            {

                ptr ->_prev ->_next = ptr ->_next;//当前节点的前面的后面变到了它的后面去了

                ptr ->_next ->_prev = ptr ->_prev;//当前节点的后面的前面变到了它的前面去了

                //现在链表就绕过了ptr重新连接起来了 ptr就可以被游离出来了

                ptr ->_next = ptr ->_prev = NULL;

                if(head ->_ptr == ptr)

                    head ->_ptr = ptr ->_next;

                free(ptr);

                head ->_num--;

            }

            return data;

        }

        ptr = ptr ->_next;

    }



    return LWH_ERRORVALUE;



}

//删除按照规则返回true(从开始到结尾,所有满足规则都要删除)

//你们可以继续扩充到 Remove_if_all  将所有满足条件的删除

//callback如果你的数据有释放的需求,请自己搞定

//这个代码是不会对你的数据进行处理的

void LWH_Remove_if_all(LWH_HeadNode * head,bool (*callback)(const LWH_DataType))

{

    while(LWH_Remove_if(head,callback) != LWH_ERRORVALUE);

    //这个代码效率稍低  但是简单明了   如果想提高效率

    //按照上面的删除规则去删除  把while写在那个里面去  这样我们的指针不需要每次都从开头开始

}



//remove        删除迭代器指针的那个位置的节点,删除之后迭代器指针 有时间就写了

//迭代器指向下一个

LWH_DataType LWH_Remove(LWH_HeadNode * head)

{

    if(!head || LWH_Empty(head) || LWH_End(head))

        return LWH_ERRORVALUE;

    LWH_DataType data = head ->_ptr ->_data;//保存你要返回的数据

    //删除头

    if(head ->_ptr == head ->_first)

    {

        LWH_Pop_Front(head);    

    }

    else if(head ->_ptr == head ->_last)//删除尾

    {

        LWH_Pop_Back(head);    

        head ->_ptr = NULL;

    }

    else//删中间

    {

        LWH_Node *ptr = head ->_ptr;//先将你要删除的节点保存起来

        head ->_ptr = head ->_ptr ->_next;//迭代器往后面指一个

        ptr ->_prev ->_next = ptr ->_next;//当前节点的前面的后面变到了它的后面去了

        ptr ->_next ->_prev = ptr ->_prev;//当前节点的后面的前面变到了它的前面去了

        //现在链表就绕过了ptr重新连接起来了 ptr就可以被游离出来了

        ptr ->_next = ptr ->_prev = NULL;

        free(ptr);

        head ->_num--;

    }

    return data;

}

//erase_after   将删除迭代器指针指向的后面的元素擦除   作业

LWH_DataType LWH_Erase_after(LWH_HeadNode * head)

{

    LWH_Node * ptr = head ->_ptr;



    //走下一个

    LWH_Next(head);

    LWH_Remove(head);



    //迭代器再回到前面的那个节点就可以了

    head ->_ptr = ptr;



}



//sort   作业,由于是基于数据进行排序,因此你要给规则

//d1 是前面节点元素  d2是后面节点元素  calback返回true的时候  d1 d2交换位置

//如果calback为空则不会排序

void LWH_Sort(LWH_HeadNode * head,bool (*callback)(const LWH_DataType d1,const LWH_DataType d2))

{

    if(!head || LWH_Length(head) < 2 || !callback)//头节点不存在或者链表的长度小于2  没有必须要排序

        return;

    for(int i = 0;i < LWH_Length(head) - 1;i++)//总趟数 Length - 1

    {

        int flag = 0;//看是否交换  如果一个都没有交换 说明已经排好了 就可以退出了

        //遍历指针

        LWH_Node * ptr = head ->_first;

        while(ptr ->_next)

        {

            //看条件进行交换

            if(callback(ptr ->_data,ptr ->_next ->_data))

            {

                flag = 1;

                LWH_DataType t;

                t = ptr ->_data;

                ptr ->_data = ptr ->_next ->_data;

                ptr ->_next ->_data = t;

            }

            ptr = ptr ->_next;

        }

        if(!flag)

            break;

    }

}



//              返回链表中的倒数第n个元素 作业

//两个指针  一个现在前面走n步 然后再一起走 前面那个走到头了,后面的那个就是倒数第n个

//错误返回 LWH_ERRORVALUE

LWH_DataType LWH_Countdown(LWH_HeadNode * head,int n)

{

    if(!head || LWH_Length(head) < n)

        return LWH_ERRORVALUE;

    LWH_Node * f = head ->_first;//前面一个

    LWH_Node * s = head ->_first;//后面一个

    //前面先走n步

    for(int i = 0;i < n;i++)

    {

        f = f ->_next;

    }

    //两个人再一起走

    while(f)

    {

        f = f ->_next;

        s = s ->_next;

    }



    return s ->_data;

}




//merge         归并两个有序的链表  有时间就写了

//head1 和 head1 都应该是升序或者降序   归并好了的链表也是有序的

//head2 归并到 head1里面去  归并完毕  head2只会剩余一个空的头节点

//callback为比较的规则

void LWH_Merge(LWH_HeadNode * head1,LWH_HeadNode * head2,bool (*callback)(const LWH_DataType d1,const LWH_DataType d2))

{

    if((!head1 || !head2))

        return;

    //将head2归并到head1里面去

    //需要三个遍历指针

    LWH_Node * p = head1 ->_first;

    LWH_Node * q1 = head2 ->_first;

    LWH_Node * q2 = head2 ->_first;//主要走q2

    while(!LWH_Empty(head2))

    {

        if(!callback(p ->_data,q2 ->_data))//不满足条件 p 往后面走

        {

            p = p ->_next;

            if(!p)//弄到最后面的后面还没有找到  那么就没得了  那么就将head2全部接到head1后面

            {

                head1 ->_last ->_next = head2 ->_first;

                head2 ->_first ->_prev = head1 ->_last;

                head1 ->_last = head2 ->_last;

                head1 ->_num += head2 ->_num;

                memset(head2,0,sizeof(*head2));

                return;

            }

        }

        else

        {

            q1 = q2;

           

            while(q2 ->_next && callback(p ->_data,q2 ->_next ->_data))

            {

                q2 = q2 ->_next;

            }//发现第一个不满足

            head2 ->_first = q2 ->_next;



            if(!LWH_Empty(head2))

            {

                //断开q2

                head2 ->_first ->_prev = NULL;

                q2 ->_next = NULL;

            }

            //将q1 ~ q2这一节全部接在p的前面

            if(p == head1 ->_first)

            {

                q2 ->_next = p;

                p ->_prev = q2;

               

                head1 ->_first = q1;

            }

            else

            {              

                p ->_prev ->_next = q1;

                q1 ->_prev = p ->_prev;

                p ->_prev = q2;

                q2 ->_next = p;

                q2 = head2 ->_first;//接完了   q2要弄到head2 ->_first

            }

        }

    }

    head1 ->_num += head2 ->_num;

    memset(head2,0,sizeof(*head2));

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值