单向链表装载用户自定义数据的c语言实现 linklistpackagenode.h 和 linklistpackagenode.c

linklistpackagenode.h 文件

#ifndef _LINKLIST_PACKAGENODE_H_
#define _LINKLIST_PACKAGENODE_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//单向链表
//链表操作精髓在于操作关系节点,引入辅助指针pcurrent,pnext.从表头开始遍历各关系节点。

//让业务节点包含关系节点,并把关系节点放在业务的首地址
//业务的首地址就是关系节点的地址,统一转化

//让无序的数据通过指针组成链表,联系起来
//1,指针指向谁就把谁的地址赋给指针
//2,分清楚链表的操作逻辑和辅助指针变量之间的关系
//3, 链表是链式存储的,无顺序,单向的,找到3必须先找到2,
//找到2必须先找到1,找到1必先找到0,再找到头,故引入辅助指针,不可以[]操作

//实现上层调用和底层分离,不让调用用户知道数据结构
typedef void List;
typedef void UserData;

#ifndef bool
#define bool int
#define true 1
#define false 0
#endif
//链表就是有很多表格组成,刚开始创建表头格,
//业务节点创建后来的表格,通过关系节点连接起来
/**链表只创建了一个链表头,next指向null。后边添加的节点是在业务节点中产生的。**/

//小节点,等待被业务节点包含。
//由小节点之间的关系连接业务节点。
//被业务节点放在首部,小节点地址与业务节点首地址重合
//链表的算法和业务分离,STL思想

//定义小节点是有联系的 ,小节点的链表
typedef struct _tag_LinkListConnectedNode
{
    struct _tag_LinkListConnectedNode* next;
}LinkListConnectedNode;

//定义链表头, 头部链表
typedef struct _tag_LinkList{
    LinkListConnectedNode head;  //小节点
    int length; //小节点的个数就相当于业务节点的个数
}LinkList;
//定义用户链表
typedef struct _tag_LinkListUser
{
    LinkListConnectedNode head;  //小节点
    UserData* item;
}LinkListUser;
//用户定义的数据业务模型只要包含关系节点,且关系的节点的地址与表头的关系节点地址相当
//都是每个表格的首地址即可,业务节点就可以与表头串起来
//typedef struct _tag_LinkListData
//{
//  LinkListConnectedNode node;   //关系节点
//  Teacher teacher;     //业务数据
//}LinkListData;

List* LinkList_create();
bool LinkList_destory(List* list);
bool LinkList_clear(List* list);
int LinkList_getLength(List* list);
bool LinkList_insertOneNode(List* list ,UserData* listuserdata, int pos);
UserData* LinkList_getOneNode(List* list, int pos );
UserData* LinkList_deleteOneNode(List* list, int pos);
bool LinkList_deleteAllNode(List* list);
#endif

linklistpackagenode.c 文件

#include "linklistpackagenode.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//底层函数分配链表头和业务链表的内存,注意内存管理
//底层函数分配业务链表关系连接节点的内存,业务链表包含了待操作数据的节点
//对链表的操作实际是通过关系连接节点的操作完成的
//各链表的首地址就是关系连接节点的地址
//链表头的首地址就是第一个关系连接节点的地址
//链表头不存业务数据
//链表操作精髓在于操作关系节点,引入辅助指针pcurrent,pnext.从表头开始遍历各关系节点。

//每次增加新业务节点时,只需业务创建业余节点,通过关系节点连接起来
//业务节点和链表头都要包含关系节点。
List* LinkList_create()
{
    //只创建一个头结点
    List* ret = NULL;
    LinkList* templinklist = NULL;
    templinklist = (LinkList*)malloc(sizeof(LinkList));
    memset(templinklist,0,sizeof(LinkList));
    templinklist->head.next = NULL;
    templinklist->length = 0;
    ret = (List*)templinklist;
    return ret;
}
//销毁链表先清空链表在释放表头内存
bool LinkList_destory(List* list)
{   
    bool ret;
    LinkList* templinklist = NULL;
    if (list == NULL)
    {
        return false;
    }
    templinklist = (LinkList*)list;
    ret = LinkList_clear((List*)templinklist);
    if (ret == false)
    {
        return false;
    }
    if (templinklist != NULL)
    {
        free(templinklist);
        templinklist = NULL;
    }

    return true;
}
//清空链表先删除所有业务节点,只保留表头,注意内存释放
bool LinkList_clear(List* list)
{
     bool ret;
     LinkList* templinklist = NULL;
     if (list == NULL)
     {
         return false;
     }
     templinklist = (LinkList*)list;
     ret = LinkList_deleteAllNode((List*)templinklist);
     if (ret == false)
     {
         return false;
     }
     if (templinklist != NULL)
     {
         templinklist->length = 0;
         templinklist->head.next = NULL;
     }
     return true;
}

int LinkList_getLength(List* list)
{
    int ret = 0;
    LinkList* templinklist = NULL;
    if (list == NULL)
    {
        return -1;
    }
    templinklist = (LinkList*)list;
    ret = templinklist->length;
    return ret;
}
//用户节点转换为链表节点,底层函数分配链表业务节点的内存
bool LinkList_insertOneNode(List* list ,UserData* userdata, int pos)
{
    LinkList* templinklist = NULL;
    LinkListConnectedNode* pcurrent = NULL; //辅助指针
    LinkListConnectedNode* linklistconnectednode = NULL;
    int i = 0;
    //业务链表
    LinkListUser* linklistuser = NULL;
    if (list == NULL || userdata == NULL || pos < 0)
    {
        return false;
    }
    templinklist = (LinkList*)list;
    //底层函数为业务链表分配内存
    linklistuser = (LinkListUser*)malloc(sizeof(LinkListUser));
    //初始化
    memset(linklistuser,0,sizeof(LinkListUser));
    if (linklistuser == NULL)
    {
        return false;
    }
    //代操作的数据转换为业务链表的节点
    linklistuser->item = userdata;
    //业务链表首地址就是关系连接的节点,利用关系连接节点操作
    linklistconnectednode = (LinkListConnectedNode*)linklistuser;
    //辅助指针指向链表的头部,带头的链表,头部之后就是0位置存业务节点;
    //头部只存小节点,不存业务节点。头部只是指向整个链表的首地址
    pcurrent = &(templinklist->head); 
    //辅助指针从头部跳到(pos-1) 处;头部、0、1、2、。。
    for ( i = 0; (i < pos && (pcurrent->next != NULL)); i++)
    {
        pcurrent = pcurrent->next;
    }
    //头,0,1,2,3,4, 要在3号插入,pcurrent 指向2,pcurrent->next 指向3
    //插入新节点后,新节点的next应该指向原来的3即上面的pcurrent->next,pcurrent->next应该指向新节点了
    //当前节点的next 指向要插入新节点的next
    linklistconnectednode->next = pcurrent->next;
    //当前节点的next指向要插入新节点的地址
    pcurrent->next = linklistconnectednode;
    templinklist->length++;
    return true;
}
//得到链表的业务节点
UserData* LinkList_getOneNode(List* list, int pos )
{
    LinkList* templinklist = NULL;
    LinkListConnectedNode* pcurrent = NULL; //辅助指针
    UserData* ret = NULL;
    int i = 0;
    //业务链表
    LinkListUser* linklistuser = NULL;
    if (list == NULL || pos < 0)
    {
        return NULL;
    }
    templinklist = (LinkList*)list;
    if (templinklist->length <= 0 || pos >= templinklist->length)
    {
        return NULL;
    }
    //辅助指针指向链表的头部,带头的链表,头部之后就是0位置存业务节点;
    //头部只存小节点,不存业务节点。头部只是指向整个链表的首地址
    pcurrent = &(templinklist->head); //辅助指针指向链表头部
    //辅助指针从头部跳到(pos-1) 处;头部、0、1、2、。。
    for (i = 0; (i < pos && (pcurrent->next != NULL)); i++) //跳pos次,到pos-1处,刚开始指向头部,跳1次指向0
    {
        pcurrent = pcurrent->next;
    }
    //得到业务链表节点
    linklistuser = (LinkListUser*)(pcurrent->next);
    ret  = (UserData*)(linklistuser->item);
    return ret;
}
//删除链表的业务节点,由于业务节点时底层分配的,还需要底层释放
UserData* LinkList_deleteOneNode(List* list, int pos)
{
    LinkList* templinklist = NULL;
    LinkListConnectedNode* pcurrent = NULL; //辅助指针
    LinkListConnectedNode* pdelete = NULL; //缓存要删除的节点
    UserData* ret = NULL;
    int i = 0;
    LinkListUser* linklistuser = NULL;
    if (list == NULL || pos < 0)
    {
        return NULL;
    }
    templinklist = (LinkList*)list;
    if (templinklist->length <= 0 || pos >= templinklist->length)
    {
        return NULL;
    }
    //辅助指针指向链表的头部,带头的链表,头部之后就是0位置存业务节点;
    //头部只存小节点,不存业务节点。头部只是指向整个链表的首地址
    pcurrent = &(templinklist->head); //辅助指针指向链表头部
    //辅助指针从头部跳到(pos-1) 处;头部、0、1、2、。。
    for (i = 0; (i < pos && (pcurrent->next != NULL)); i++) //跳pos次,到pos-1处,刚开始指向头部,跳1次指向0
    {
        pcurrent = pcurrent->next;
    }
    //得到要删除的节点
    pdelete = pcurrent->next;
    pcurrent->next = pdelete->next;
    templinklist->length--;
    //删除的业务节点
    linklistuser =(LinkListUser*)pdelete;
    ret = (UserData*)linklistuser->item;
    //释放业务节点内存
    if (linklistuser != NULL)
    {
        free(linklistuser);
        linklistuser = NULL;
    }
    return ret;
}

bool LinkList_deleteAllNode(List* list)
{
    LinkList* templinklist = NULL;
    if (list == NULL)
    {
        return false;
    }
    templinklist = (LinkList*)list;
    while(templinklist->length > 0)
    {
        LinkList_deleteOneNode(list,0);
    }
    return true;
}

/***********************以下为测试代码************************/

/*

//方法1:在业务节点中定义链表的一格的关系节点
//typedef struct _tag_Teacher{
//  LinkListConnectedNode node;
//  int age;
//  char name[64];
//}Teacher;

//方法2:把业务直接定义到链表一格的关系节点之下
//用户定义的数据业务模型只要包含关系节点,
//且关系的节点的地址与表头的关系节点地址相当
//都是每个表格的首地址即可,业务节点就可以与表头串起来
typedef struct _tag_Teacher{
    int age;
    char name[64];
}Teacher;


void main()
{

    int k = 0;
    List* list = NULL;
    Teacher t1,t2,t3,t4,t5;
    t1.age = 21;t2.age = 22;t3.age = 23;t4.age = 24;t5.age = 25;
    list = LinkList_create();
    if (list == NULL)
    {
        printf("list创建失败");
    }

    //头插法,插入元素
    //业务节点强制转换为ListNode* ,ListNode* 强制转换为小节点LinkListConnectedNode*;
    LinkList_insertOneNode(list,(UserData*)&t1,0);
    LinkList_insertOneNode(list,(UserData*)&t2,0);
    LinkList_insertOneNode(list,(UserData*)&t3,0);
    LinkList_insertOneNode(list,(UserData*)&t4,0);
    LinkList_insertOneNode(list,(UserData*)&t5,0);
    printf("链表长度是:%d \n", LinkList_getLength(list));
    //遍历链表
    for (k = 0; k < LinkList_getLength(list); k ++)
    {
        Teacher* teachertemp = (Teacher* )LinkList_getOneNode(list,k); 
        printf("老师%d的年龄是%d \n",k+1,teachertemp->age);
    }
    LinkList_deleteAllNode(list);
    printf("链表长度是:%d \n", LinkList_getLength(list));
    LinkList_destory(list);
    system("pause");
}
*/

可能会调用其它头文件会源文件,如果遇到,请翻看我的其它博客,对其头文件或源文件的实现方式。
good luck !

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值