2-另一种形式的单向链表

笔记

另一种形式的单向链表

节点结构体并不存储数据,只有一个next指针元素。然后约定好数据结构体预留四个字节(结构体定义时的最上方,地址的低四字节)。当数据指针和节点指针互相转换时,next元素就映射至数据预留的四字节,即可用来做指针指向下一节点。这样可以让数据和链表更分离,链表可以不再维护数据。

代码

start0.c

#include<stdlib.h>
#include<stdio.h>

//节点
struct linkNode{
    void* next;
};

//管理节点
typedef struct{
    struct linkNode head;
    int m_size;
}linkListType;

//初始化链表
linkListType* init_link(){
    linkListType* llt = malloc(sizeof(linkListType));
    return llt;
}

//按位置插入数据
void insert_link(linkListType* plist,int pos, void* data){
    if(NULL == plist){
        return;
    }
    if(pos < 0 || pos > plist->m_size){
        pos = plist->m_size;
    }
    //将data转成linkNode类型,这样linkNode的低4字节和data的低4字节重合
    struct linkNode* myNode = data;  //myNode既是要插入节点的指针,它的前4字节又被提供出来做next字段
    struct linkNode* currNode = &(plist->head);

    //找到要插入位置的前驱节点
    for(int i=0;i<pos;i++){
        currNode = currNode->next;
    }

    myNode->next = currNode->next;  //要插入节点的next指向下一节点
    currNode->next = myNode;        //前驱节点的next指向要插入的节点

    plist->m_size++;
}

//遍历
void foreach_link(linkListType* plist,void(*myforeach)(void*)){
    if(NULL == plist){
        return;
    }

    struct linkNode* currNode = &plist->head;
    for(int i=0;i<plist->m_size;i++){
        currNode = currNode->next;
        myforeach(currNode);
    }
}

//通过位置删除链表节点
void remove_link(linkListType* plist, int pos){
    if(NULL == plist){
        return;
    }
    if(pos < 0 || pos >= plist->m_size){
        pos = plist->m_size-1;
    }

    //找到位置的前置节点
    struct linkNode* currNode = &plist->head;
    for(int i=0; i<pos; i++){
        currNode = currNode->next;
    }

    //记录要删除的数据
    struct linkNode* delNode = currNode->next;

    //修改指向,将前驱节点的next指向 要删除节点 的后驱节点
    currNode->next = delNode->next;

    //不要在这里释放delNode,链表不维护数据

    plist->m_size--;
}

//清空链表
void clear_link(linkListType* plist){
    if(NULL == plist){
        return;
    }

    struct linkNode* currNode = &plist->head;
    struct linkNode* delNode = NULL;

    for(int i=0; i<plist->m_size; i++){
        delNode = currNode;  //要清除的节点

        currNode = currNode->next;

        delNode = NULL;
    }
    plist->m_size = 0;
}

//按照约定,数据的低4字节存储next指针
struct Persion{
    void* node;
    char m_name[64];
    int m_age;
};

void myForEach(void* data){
    struct Persion* p = data;

    printf("name=%s\tage=%d\n",p->m_name, p->m_age);
}

int main(){
    linkListType* plist = init_link();

    struct Persion p1 = {NULL,"aaa",10};
    struct Persion p2 = {NULL,"bbb",20};
    struct Persion p3 = {NULL,"ccc",30};

    insert_link(plist,0,&p1);
    insert_link(plist,0,&p2);
    insert_link(plist,1,&p3);

    foreach_link(plist,myForEach);

    remove_link(plist,1);

    printf("------------------------\n");
    foreach_link(plist,myForEach);

    clear_link(plist);
    printf("------------------------\n");
    foreach_link(plist,myForEach);

    free(plist);

    return 0;
}
posted @ 2022-01-25 20:49  WuYunTaXue  阅读(31)  评论(0编辑  收藏  举报