C语言-企业级链表

视频【C语言数据结构 培养架构师思维】 P12-P13内容
https://www.bilibili.com/video/BV1Pb411g7bU/?share_source=copy_web&vd_source=1f125f59acec416a3d726792acdc05fd

同单链表最大的区别:链表结点只需要维护指针域,不需要维护数据域,交给用户自己维护,需要用户预留前四个字节,用来存地址。

main.c

//企业级开发
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


//链表结点,只需要维护指针域,不需要维护数据域,交给用户自己维护,需要用户预留前四个字节,用来存地址
struct LinkNode
{
    struct LinkNode* next;  //指针域
};

//链表结构体
struct LList
{
    struct LinkNode pHeader;    //头结点
    int m_Size;     //链表长度
};

typedef void* LinkList;

//初始化链表
LinkList Init_LinkList()
{
    struct LList* myList = malloc(sizeof(struct LList));
    
    if(myList == NULL)
    {
        return NULL;
    }
    
    //初始化链表结构体
    myList->pHeader.next = NULL;
    myList->m_Size = 0;
    
    return myList;
    
}


//插入结点
void Insert_LinkList(LinkList List, int pos, void* data)
{
    if(List == NULL)
    {
        return;
    }   
    if(data == NULL)
    {
        return;
    } 
    
    struct LList* myList = List;
    
    //无效位置进行尾插
    if(pos<0 || pos>myList->m_Size)
    {
        pos = myList->m_Size;
    }
        
    //将用户的数据的前四个字节转为LinkNode类型,myNode这个指针变量的步长为4字节
    struct LinkNode* myNode = data;

    struct LinkNode* pCurrent = &myList->pHeader;
    //找到插入位置的前驱结点
    for(int i = 0; i<pos; i++)
    {
        pCurrent = pCurrent->next;
    }
    
    //将新结点插入链表
    myNode->next = pCurrent->next;
    pCurrent->next = myNode;
    
    
    //链表大小+1
    myList->m_Size++;
    
}

//遍历链表
void Foreach_LinkList(LinkList List, void(*MyPrintf)(void*))
{
    if(List == NULL)
    {
        return;
    } 
    
    struct LList* myList = List;
    
    //找到第一个有数据的节点
    struct LinkNode* pCurrent = myList->pHeader.next;
    
    for(int i = 0; i<myList->m_Size; i++)
    {
        MyPrintf(pCurrent);
        pCurrent = pCurrent->next;
        
    }  
}


//按位置删除结点
void RemoveByPos_LinkList(LinkList List, int pos)
{
    if(List == NULL)
    {
        return;
    }   

    struct LList* myList = List;

    //无效位置删除
    if(pos<0 || pos>myList->m_Size-1)
    {
        return;
    }

    //找到删除结点的前驱结点
    struct LinkNode* pCurrent = &myList->pHeader;
    for(int i = 0; i<pos; i++)
    {
        pCurrent = pCurrent->next;
    }

    //待删除的结点
    struct LinkNode* pDel = pCurrent->next;

    //更改指针指向,修改待删除结点的前驱结点指向,指向待删除结点的后驱结点
    pCurrent->next = pDel->next;

    //!!!!!!释放掉待删除的结点,此处不再需要了,数据域不再需要维护了,让用户自己管理
    // free(pDel);
    // pDel = NULL;

    //更新链表长度
    myList->m_Size--;
    
}

//按值删除结点
void RemoveByValue_LinkList(LinkList List, void* data, int(*mycompare)(void* data1, void* data2))
{
    if(List == NULL)
    {
        return;
    }      

    if(data == NULL)
    {
        return;
    }
    struct LList* myList = List;

    //创建两个辅助指针变量,第一个指向当前结点的前驱结点,第二个指向当前节点
    struct LinkNode* pPrev = &myList->pHeader;
    struct LinkNode* pCurrent = pPrev->next;

    for(int i = 0; i < myList->m_Size; i++)
    {
        if(mycompare(pCurrent, data))
        {
            //更改指针指向
            pPrev->next = pCurrent->next;

            myList->m_Size--;

            break;
        }

        //每循环一次,数据比对不一致时,结点都往后移动一个
        pPrev = pCurrent;
        pCurrent = pCurrent->next;

    }

    return;
}

//销毁链表
void Destory_LinkList(LinkList List) 
{
    if(List == NULL)
    {
        return;
    }  

    free(List);
    return;    
}

struct Person
{
    struct LinkNode node;//约定好的前四个字节给底层链表使用  //void* aaa;只要让用户留四个字节就可以
    char name[64];
    int age;
};

//输出函数,用于遍历
void MyPrintf(void* data)
{
    struct Person* p = data;
    printf("姓名:%s    年龄:%d    \n", p->name, p->age);
}

//比较函数,用于对比数值,一致返回1,不一致返回0
int MyComparePerson(void*data1, void* data2)
{
    struct Person* p1 = data1;
    struct Person* p2 = data2;

    return (strcmp(p1->name, p2->name) == 0) && (p1->age == p2->age);
}


int main()
{
    //初始化链表
    LinkList myList =  Init_LinkList();
    
    //插入数据
    struct Person p1= {NULL, "小一", 11};
    struct Person p2= {NULL, "小二", 12};
    struct Person p3= {NULL, "小三", 13};
    struct Person p4 = {NULL, "小四", 14};
    struct Person p5 = {NULL, "小五",15};
    struct Person p6 = {NULL, "小六", 16};
    struct Person p7 = {NULL, "小三", 13};
    struct Person p8 = {NULL, "小八", 18};    
 
    printf("//\n");

    //插入
    Insert_LinkList(myList, 0, &p1 );
    Insert_LinkList(myList, 0, &p2 );
    Insert_LinkList(myList, 2, &p3 );
    Insert_LinkList(myList, 10, &p4 );
    Insert_LinkList(myList, 1, &p5 );
    Insert_LinkList(myList, 4, &p6 );
    
    //遍历输出链表
    printf("插入后的链表:\n");
    Foreach_LinkList(myList, *MyPrintf);//理想顺序:小二     小五    小一    小三    小六    小四  
    printf("//\n");

   //通过位置删除,并遍历
    RemoveByPos_LinkList(myList, 2);    
    printf("按位置删除后的链表:\n");
    Foreach_LinkList(myList, *MyPrintf);//理想顺序:小二     小五     小三    小六    小四 
    printf("//\n");

    //通过值来删除,并遍历
    RemoveByValue_LinkList(myList, &p7, *MyComparePerson);
    printf("按值删除后的链表:\n");
    Foreach_LinkList(myList, *MyPrintf);//理想顺序:小二     小五    小六    小四 
    printf("//\n");

    //通过值来删除,并遍历
    RemoveByValue_LinkList(myList, &p8, *MyComparePerson);
    printf("按值删除后的链表:\n");
    Foreach_LinkList(myList, *MyPrintf);//理想顺序:小二     小五    小六    小四 

    //销毁动态数组
    Destory_LinkList(myList);


     
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值