c语言数据结构 - 线性表的链式存储

概述

NULL

code

#include "LinkList.h"

// 自定义数据类型
typedef struct PERSON{
    char name[64];
    int age;
    int score;
}Person;

// test 函数
void test02();
void test03();
void test04();

// 用户自定义 打印函数
void myPrint(void*);

int main(int argc, char **argv){
    
    test04();
    
    return 0;
}

void test02(){
    // 1. 创建一个链表
    LinkList* list = Init_LinkList();

    // 2. 插入数据
    // 2-1 创建数据
    Person p1 = {"aaa", 18, 100};
    Person p2 = {"bbb", 17,  90};
    Person p3 = {"ccc", 16,  80};
    Person p4 = {"ddd", 15,  70};
    Person p5 = {"eee", 14,  60};

    // 2-2 数据插入链表 都插入第一个
    Insert_LinkList(list, 0, &p1); 
    Insert_LinkList(list, 0, &p2);
    Insert_LinkList(list, 0, &p3);
    Insert_LinkList(list, 0, &p4);
    Insert_LinkList(list, 0, &p5);

    // 3 打印数据
    Print_LinkList(list, myPrint);

    // 4 销毁链表
    FreeSpace_LinkList(list);    
}

void test03(){
    // 1. 创建一个链表
    LinkList* list = Init_LinkList();

    // 2. 插入数据
    // 2-1 创建数据
    Person p1 = {"aaa", 18, 100};
    Person p2 = {"bbb", 17,  90};
    Person p3 = {"ccc", 16,  80};
    Person p4 = {"ddd", 15,  70};
    Person p5 = {"eee", 14,  60};

    // 2-2 数据插入链表 都插入第一个
    Insert_LinkList(list, 0, &p1); 
    Insert_LinkList(list, 0, &p2);
    Insert_LinkList(list, 0, &p3);
    Insert_LinkList(list, 0, &p4);
    Insert_LinkList(list, 0, &p5);

    // 3 打印数据
    Print_LinkList(list, myPrint);


    // 4 删除数据 - 3号数据
    RemoveByPos_LinkList(list, 3);

    // 5 打印数据
    Print_LinkList(list, myPrint);

    // 6 销毁链表
    FreeSpace_LinkList(list);    
}

void test04(){
    // 1. 创建一个链表
    LinkList* list = Init_LinkList();

    // 2. 插入数据
    // 2-1 创建数据
    Person p1 = {"aaa", 18, 100};
    Person p2 = {"bbb", 17,  90};
    Person p3 = {"ccc", 16,  80};
    Person p4 = {"ddd", 15,  70};
    Person p5 = {"eee", 14,  60};

    // 2-2 数据插入链表 都插入第一个
    Insert_LinkList(list, 0, &p1); 
    Insert_LinkList(list, 0, &p2);
    Insert_LinkList(list, 0, &p3);
    Insert_LinkList(list, 0, &p4);
    Insert_LinkList(list, 0, &p5);

    // 3 打印数据
    Print_LinkList(list, myPrint);

    // Person* pe = (Person*)Front_LinkList(list);
    myPrint(Front_LinkList(list));

    // 4 销毁链表
    FreeSpace_LinkList(list);    
}

void myPrint(void* data){
    // 1. 将数据data进行类型转换
    Person* p = (Person*)data;

    // 2. 打印数据
    printf("Name: %s\t Age: %d\t Score: %d\n", p->name, p->age, p->score);
}
#include "LinkList.h"


// 1. 初始化链表
LinkList* Init_LinkList(){
    
    // 1-1 分配内存
    LinkList* list = (LinkList*)malloc(sizeof(LinkList));
    list->size = 0;

    // 1-2 保证头节点存在性:如果没有头节点需要考虑数据是否插入到头节点了;如果有头结点就不需要考虑这个问题;为了
    // 为了让链表实现起来思路更加清晰简单;带不带都可以,只不过是说带了头结点问题会变得简单
    list->head = (LinkNode*)malloc(sizeof(LinkNode));
    list->head->data = NULL;
    list->head->next = NULL;

    return list;

}

// 2. 在指定位置插入 链表的位置是从0开始的
void Insert_LinkList(LinkList* list, int pos, void* data){

    // 2-1 判断输入的有效性
    if(list == NULL){
        return;
    }
    if(data == NULL){
        return;
    }
    // 2-1 判断位置:pos 越界;pos < 0; 的时候,默认插入尾部
    if(pos < 0 || pos > list->size){
        pos = list->size;
    }

    // 2-2 创建新的节点
    LinkNode* newnode = (LinkNode*)malloc(sizeof(LinkNode));
    newnode->data = data;
    newnode->next = NULL;

    // 2-3 寻找 pos 的前一个节点
    LinkNode* pCurrent = list->head;    // 辅助指针变量; 先让它指向list的头结点
    for(int i = 0; i < pos; i++){
        pCurrent = pCurrent->next;
    }

    // 2-4 新节点入列表
    newnode->next = pCurrent->next;
    pCurrent->next = newnode;

    list->size++;
}

// 3. 删除指定位置的值
void RemoveByPos_LinkList(LinkList* list, int pos){
    // 3-1 判断输入的有效性
    if(list == NULL){
        return;
    }
    // 3-1 判断位置:pos 越界;pos < 0;
    if(pos < 0 || pos >= list->size){
        return;
    }

    // 3-2 寻找位置的前一个节点
    LinkNode* pCurrent = list->head;
    for(int i = 0; i < pos; i++){
        pCurrent = pCurrent->next;
    }

    // 3-3 删除节点
    LinkNode* pDel = pCurrent->next;
    pCurrent->next = pDel->next;

    // 3-4 释放空间 
    free(pDel);

    list->size--;

}

// 4. 获得链表的长度
int Size_LineList(LinkList* list){
    if(list == NULL){
        return -1;
    }

    return list->size;
}

// 5. 返回第一个节点
void* Front_LinkList(LinkList* list){
    return list->head->next->data;        // 若该链表为空,那么就返回NULL
}

// 6. 释放链表内存
void FreeSpace_LinkList(LinkList* list){
    if(list == NULL){
        return;
    }

    // 6-1 释放内存; 每一个节点的内存都是手动分配,所以每一个节点都需要手动释放,需要变量
    LinkNode* pCurrent = list->head;
    LinkNode* pNext = NULL;
    while(pCurrent != NULL){
        pNext = pCurrent->next;
        free(pCurrent);
        pCurrent = pNext;
    }

    // 6-2 释放链表内存
    free(pNext);
    list->size = 0;             // 可写可不写,习惯写上
    free(list);
}

// 7. 查找某个值 根据指针(地址)来查找某个值 
int Find_LinkList(LinkList* list, void* data){

    // 7-1 有效性判断
    if(list == NULL){
        return -1;
    }
    if(data == NULL){
        return -1; 
    }

    // 7-2 遍历查找
    LinkNode* pCurrent = list->head->next;      // 因为head不保存数据,所以将其执行head的下一个节点 
    int i = 0;
    for(; i < list->size; i++){
        if(pCurrent->data == data)
            break;
        pCurrent = pCurrent->next;
    }

    return i;
}

// 8. 打印链表节点 事先不知道data是什么类型的;开发者不确定的事情,让用户去完成
// 这样每一次打印的时候,调用用户传递进来的函数即可 print 是打印函数指针 
void Print_LinkList(LinkList* list, PRINTLINKNODE print){
    if(list == NULL){
        return;
    }

    // 打印数据
    LinkNode* pCurrent = list->head->next;
    while(pCurrent != NULL){
        // 打印数据,因为不知道数据类型,调用用户传进来的函数
        print(pCurrent->data);
        pCurrent = pCurrent->next;
    }

    printf("---------------------------------------\n");
}
#ifndef LINK_LIST_H
#define LINK_LIST_H


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

/**
 * @brief 线性表的链式存储:用不连续的内存空间、
 * 
 * 链表是由一系列的节点组成,每个节点包括两个域,指针域和数字域;需要指针域保存下一个节点的地址;
 * 当指针域指向为NULL,代表链表结束
 * 
 * 若想要插入一个新的节点。首先需要找到该位置的前一个节点,使用新的节点的指针域指向前一个节点的后一个节点;最后将前一个节点的指针域指向新的节点的首地址
 * 
 * 若想要删除一个节点,首先需要找到该节点和它前一个节点,其次让前一个节点的指针域指向该节点的下一个节点,最后让该节点的指针域设置为空,释放该节点的内存
 */

// 0-1. 链表节点
typedef struct LINKNODE{
    void* data;            // 无类型指针:使用无类型指针指向任意数据类型的数据
    struct LINKNODE* next;
}LinkNode;


// 0-2. 建立链表
typedef struct  LINKLIST{
    LinkNode* head;         // 头节点
    int size;               // 链表的大小
    // 不需要容量
}LinkList;
  

// 0-3 打印函数指针: 形参类型是 void*, 返回值是 void
typedef void(*PRINTLINKNODE)(void *);

// 1. 初始化链表
LinkList* Init_LinkList();

// 2. 在指定位置插入
void Insert_LinkList(LinkList* list, int pos, void* data);

// 3. 删除指定位置的值
void RemoveByPos_LinkList(LinkList* list, int pos);

// 4. 获得链表的长度
int Size_LineList(LinkList* list);

// 5. 返回第一个节点
void* Front_LinkList(LinkList* list);

// 6. 释放链表内存
void FreeSpace_LinkList(LinkList* list);

// 7. 查找某个值 根据指针来查找某个值
int Find_LinkList(LinkList* list, void* data);

// 8. 打印链表节点 事先不知道data是什么类型的;开发者不确定的事情,让用户去完成
// 这样每一次打印的时候,调用用户传递进来的函数即可 print 是打印函数指针 
void Print_LinkList(LinkList* list, PRINTLINKNODE print);
 

#endif

# 执行指令
gcc -fPIC -shared LinkList.c -o liblinkList.so
gcc main.c -o main -L ./ -llinkList -Wl,-rpath ./
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值