数据结构-面向用户的单向链表-C描述

面向用户的单向链表

此链表面向用户,用户在定义数据时预留出指针位置,开发人员操作时仅仅操作用户的前四个内存位置 ,可大大提高效率!
例如:

typedef struct Person{
    //预留出四个字节的指针
    //预留的目的是开发人员进行维护链表指针

    void *node;//预留出指针位置
    char name[64];
    int age;
}Person;

模型展示
在这里插入图片描述

代码实现展示

** 注释非常详细可直接编译运行**

//
// Created by wen on 2021/9/18.
//企业级开发单向链表
//
#include <stdio.h>
#include "string.h"
#include "stdlib.h"
//定义节点结构
typedef struct LinkNode {
    //只维护指针域
   struct LinkNode *next;
}LinkNode;

//定义链表结构
typedef struct LList{
    LinkNode pHeader;
    int m_size;
}LList;
//不想让用户直接拿到链表
typedef void * LinkList;

//初始化链表
LinkList * init_LinkList(){
    LList *myList = malloc(sizeof (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;
    }
    //还原链表结构
    LList * myList = List;
    //判断位置是否正确,不正确位置进行尾插
    if(pos<0||pos>myList->m_size-1)
    {
        pos = myList->m_size;
    }
    //企业级开发,开发人员仅仅维护用户前四个字节
    LinkNode* myNode = data;
    //找插入节点的前驱节点
    LinkNode * pCurrent = &(myList->pHeader);
    //使用for循环一步一步找前驱节点
    for (int i = 0; i <pos ; ++i) {
        pCurrent = pCurrent->next;
    }
    //经历循环后pcurrent就是插入的前驱位置

    //更改指针指向
    myNode->next = pCurrent->next;
    pCurrent->next = myNode;
    //更新链表长度
    myList->m_size++;
}

//遍历链表
void foreach_LinkList(LinkList List,void (*foreach_print)(void *)){
    if(List==NULL)
    {
        return;
    }
    //还原链表结构体
    LList *myList =List;
    //找到有数据的那个结点
    LinkNode * myNode = myList->pHeader.next;
    //进行遍历
    for (int i = 0; i <myList->m_size ; ++i) {
        //因为只传出地址,故需要回调函数
        foreach_print(myNode);
        //指针偏移
        myNode = myNode->next;
    }
}
//删除
//按位置进行删除
void DeleteByPos_Linklist(LinkList List, int pos){
    if(List==NULL){
        return;
    }
    //还原链表
    LList * myList = List;
    //删除位置不正确判断
    if(pos<0||pos>myList->m_size-1)
    {
        return;
    }
    //遍历找前驱指针
    LinkNode *pCurrent = &myList->pHeader;
    //开始遍历
    for (int i = 0; i < pos;++i)
    {
        pCurrent= pCurrent->next;
    }
    //pcurrent 为前驱,记录一下待删除的节点
    LinkNode *pre_node = pCurrent->next;
    //更改指针指向
    pCurrent->next = pre_node->next;

    //注意
    //不能直接写free(),因为数据是用户给的,我们只维护前四个空间,不知道用户是在哪里开辟的数据
    //让用户自己去释放

    //更新链表长度
    myList->m_size--;
}
//按照值进行删除
void DeleteByValue_LinkList(LinkList List, void *data ,int (*Compare)(void* ,void *)){
    if(List ==NULL)
    {
        return;
    }
    if(data ==NULL){
        return;
    }
    LList *myList = List;
    LinkNode * pCurrent = &myList->pHeader;
    //储存删除的元素
    LinkNode *pDel = pCurrent->next;
    for (int i = 0; i < myList->m_size; ++i) {
        if(Compare(pDel,data))
        {
            //更新节点关系
            pCurrent->next = pDel->next;
            //更新链表长度
            myList->m_size -- ;
            break;
        }
        //指针后移
        pCurrent = pDel;
        pDel= pDel->next;
    }
    myList->m_size--;

}
//清空就是把链表全部断
//数据用户自己释放
void clear_LinkList(LinkList List){
    if(List == NULL)
    {
        return;
    }
    //还原链表
    LList * myList = List;
    LinkNode * pCurrent = &myList->pHeader;
    for (int i = 0; i <myList->m_size ; ++i) {
        LinkNode * prev= pCurrent->next;
        pCurrent ==NULL;
        pCurrent = prev;
    }
    //更新
    myList->pHeader.next = NULL;
    myList->m_size=0;
}
//销毁
void destroy_LinkList(LinkList List){
    if(List == NULL)
    {
        return;
    }
    free(List);
    List ==NULL;
    printf("销毁成功\n");

}

//____________________________________________________________________________________
//测试
typedef struct Person{
    //预留出四个字节的指针
    //预留的目的是开发人员进行维护链表指针

    void *node;
    char name[64];
    int age;
}Person;
//打印函数(回调函数)
void print_Person(void *data){
    Person *P1 = data;
    printf("name:%s,age:%d\n",P1->name,P1->age);
}
//值比较的回调函数
int PersonCompare(void *data1 , void * data2){
    Person *p1 =data1;
    Person *p2 =data2;
    return strcmp(p1->name,p2->name)==0 && p1->age == p2->age;

}

//test为测试函数
void test() {
    //初始化
    LinkList *myList = init_LinkList();
    //测试数据
    Person P1 = {NULL,"tom1", 1};
    Person P2 = {NULL,"tom2", 2};
    Person P3 = {NULL,"tom3", 3};
    Person P4 = {NULL,"tom4", 4};
    Person P5 = {NULL,"tom5", 5};
    Person P6 = {NULL,"tom6", 6};
    Person P7 = {NULL,"tom7", 7};
    Person P8 = {NULL,"tom8", 8};
    Person P9 = {NULL,"tom9", 9};
    Person P10 = {NULL,"tom10", 10};
    Person a[10]={P1,P2,P3,P4,P5,P6,P7,P8,P9,P10};
    //插入
    for (int i=0; i<10;i++){
        insert_LinkList(myList,0,a+i);
    }
    //遍历链表
    foreach_LinkList(myList,print_Person);
    //位置删除
    DeleteByPos_Linklist(myList,2);
    printf("del_byPos\n");
    foreach_LinkList(myList,print_Person);
    //按照值来删除
    DeleteByValue_LinkList(myList,&P6,PersonCompare);
   // clear_LinkList(myList);
    printf("del_byValue\n");
    foreach_LinkList(myList,print_Person);
    //销毁
    destroy_LinkList(myList);
    myList == NULL;

}

void main(){
    test();
}

程序实例图

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

toptap8_nn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值