[day08]单向链表基本操作、结构体高级(Linux内核链表)、Wmblinklist动态库的调用...

1.单向链表基本操作

单向链表的创建,插入,删除,销毁,逆置

链表的结构定义

typedef struct _PtList {
         int data;
         struct _PtList *pNext;
}PtList;

链表的创建(带头节点)

// 键盘一直输入,直到输入-1为止
// 可以选择用二级指针传出结果
PtList *createList()
{
    PtList *pHead = NULL;
    int data;
    PtList *pNew = NULL;
    PtList *pCur = NULL;

    pHead = (PtList *)malloc(sizeof(PtList));
    if (pHead == NULL) {
        printf("malloc err.\n");
        return NULL;
    }
    pHead->data = 0;
    pHead->pNext = NULL;
    pCur = pHead;

    do {
        printf("请输入你的数据: ");
        scanf("%d", &data);
        if (data == -1)
            break;
        pNew = (PtList *)malloc(sizeof(PtList));
        pNew->data = data;
        pNew->pNext = NULL;

        pCur->pNext = pNew;
        pCur = pNew;
    } while (data != -1);

    return pHead;
}

往链表中插入元素

// 在值为x的元素之前插入y,若没找到则在末尾插入
int insertList(PtList *pHead, int x, int y)
{
    PtList *pTmp = NULL;
    PtList *pPri = NULL;
    PtList *pNew = NULL;
    int ret = 0;
    if (pHead == NULL) {
        printf("List is empty.\n");
        ret = -1;
        return ret;
    }

    pTmp = pHead->pNext;
    pPri = pHead;

    while (pTmp != NULL) {
        if (pTmp->data == x)
            break;
        pPri = pTmp;
        pTmp = pTmp->pNext;
    }

    pNew = (PtList *)malloc(sizeof(PtList));
    pNew->data = y;
    pNew->pNext = pTmp;
    
    pPri->pNext = pNew;

    return ret;
}

从链表中删除元素

int deleteList(PtList *pHead, int x)
{
    PtList *pTmp = NULL;
    PtList *pPri = NULL;
    int ret = 0;

    if (pHead == NULL) {
        printf("List is empty.\n");
        ret = -1;
        return ret;
    }

    pTmp = pHead->pNext;
    pPri = pHead;

    while (pTmp != NULL) {
        if (pTmp->data == x) {
            pPri->pNext = pTmp->pNext;
            free(pTmp);
            break;
        }

        pPri = pTmp;
        pTmp = pTmp->pNext;
    }

    return ret;
}

链表中元素的打印

int displayList(PtList *pHead)
{
    PtList *pTmp = NULL;
    int ret = 0;
    if (pHead == NULL || pHead->pNext == NULL) {
        printf("List is empty.\n");
        ret = -1;
        return ret;
    }

    pTmp = pHead->pNext;

    while (pTmp != NULL) {
        printf("%d\n", pTmp->data);
        pTmp = pTmp->pNext;
    }

    return ret;
}

整个链表的销毁

// 释放之后将pHead置NULL
int destoryList(PtList **pHead)
{
    PtList *pTmp = NULL;
    PtList *pCur = *pHead;
    int ret = 0;

    if (pCur == NULL) {
        printf("List is empty, do not need to destory.\n");
        ret = -1;
        return ret;
    }

    pTmp = pCur;

    while (pTmp != NULL) {
        pCur = pCur->pNext;
        free(pTmp);
        pTmp = pCur;
    }

    *pHead = NULL;

    return ret;
}

链表的逆置

int reverseList(PtList *pHead)
{
    PtList *p = NULL; /* 前驱结点 */
    PtList *q = NULL; /* 当前结点 */
    PtList *t = NULL; /* 临时指向下一个结点 */
    int ret = 0;

    // 判断链表是否有效
    if (pHead == NULL) {
        ret = -1;
        printf("List is empty.\n");
        return ret;
    }

    // 判断链表是否需要逆置
    if (pHead->pNext == NULL || pHead->pNext->pNext == NULL) {
        printf("List did not need to resvers.\n");
        return ret;
    }

    // 初始化p,q的值
    p = pHead->pNext;
    q = pHead->pNext->pNext;

    while (q != NULL) {
        /* 
            这里也是有规律的(上一行赋值元素和下一行被赋值元素)
        */
        t = q->pNext;
        q->pNext = p;
        p = q;
        q = t;
    }

    //处理最后一个元素(逆置前第一个业务结点)
    pHead->pNext->pNext = NULL;

    //处理头结点的指向
    pHead->pNext = p;

    return ret;
}

int displayList(PtList *pHead)
{
    PtList *pTmp = NULL;
    int ret = 0;
    if (pHead == NULL || pHead->pNext == NULL) {
        printf("List is empty.\n");
        ret = -1;
        return ret;
    }

    pTmp = pHead->pNext;

    while (pTmp != NULL) {
        printf("%d\n", pTmp->data);
        pTmp = pTmp->pNext;
    }

    return ret;
}

逆置思路

 

测试程序主函数

int main(void)
{
    PtList *pHead = NULL;
    int ret = 0;

    pHead = createList();
    ret = displayList(pHead);
    ret = insertList(pHead, 3, 8);
    ret = displayList(pHead);
    ret = deleteList(pHead, 3);
    ret = displayList(pHead);
    ret = reverseList(pHead);
    ret = displayList(pHead);
    ret = destoryList(&pHead);

    printf("%x\n", pHead);

    system("pause");

    return 0;
}

2.结构体高级

计算结构体中元素的偏移量

/*
@TYPE 业务结构体的类型
@MEMBER 业务结构体中嵌套的链表结构体成员变量
*/
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)

计算业务结构体元素的地址

/*
@ptr 链表结构体指针变量
@TYPE 业务结构体的类型
@MEMBER 业务结构体中嵌套的链表结构体成员变量
*/
#define container_of(ptr, type, member) (type *)((char *)ptr - offsetof(type, member))

贴上一个自己写的求位置的例子

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

#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) (type *)((char *)ptr - offsetof(type, member))

typedef struct _linklist {
    struct linklist *next;
}Linklist;

typedef struct _student {
    char name[60]; // 64
    double age; // 8 (float 4)
    Linklist list;
}Student;

int main(void)
{
    Student stu;
    Linklist *list = &stu.list;
    
    printf("%d\n", offsetof(Student, list));
    printf("%d\n", container_of(list, Student, list));
    printf("%d\n", &stu);

    system("pause");

    return 0;
}
 解释图

注:Linux内核链表就是这样实现的,很好的实现了业务和数据的分离。

 

3.Wmblinklist动态库的调用

函数原型

#ifndef _MYMLINKLIST_H_
#define _MYMLINKLIST_H_

typedef void LinkList;

typedef struct _tag_LinkListNode
{
    struct _tag_LinkListNode* next;
}LinkListNode;


/*
typedef struct _tag_LinkListNode LinkListNode;
struct _tag_LinkListNode
{
    LinkListNode* next;
};
*/

LinkList* LinkList_Create();

void LinkList_Destroy(LinkList* list);

void LinkList_Clear(LinkList* list);

int LinkList_Length(LinkList* list);

int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);

LinkListNode* LinkList_Get(LinkList* list, int pos);

LinkListNode* LinkList_Delete(LinkList* list, int pos);

#endif

测试函数

#pragma comment(lib, "wmblinklist")
#include "Mylinklist.h"
#include <stdio.h>
#include <stdlib.h>

typedef struct _Teacher {
    LinkListNode list; /* 可以选择把链表元素放到开始,可以偷懒不去计算偏移量 */ 
    char name[20];
    int age;
}Teacher;

int main(void)
{
    LinkList *list = NULL;
    Teacher t1, t2, t3;
    LinkListNode *tmp = NULL;
    int i;

    t1.age = 10;
    t2.age = 20;
    t3.age = 30;

    list = LinkList_Create();
    LinkList_Insert(list, (LinkListNode *)&t1, LinkList_Length(list));
    LinkList_Insert(list, (LinkListNode *)&t2, LinkList_Length(list));
    LinkList_Insert(list, (LinkListNode *)&t3, LinkList_Length(list));

    // 显示
    for (i = 0; i < LinkList_Length(list); i++) {
        tmp = LinkList_Get(list, i);
        printf("%d\n", ((Teacher *)tmp)->age);
    }

    // 删除
    for (i = 0; i < LinkList_Length(list); i++) {
        LinkList_Delete(list, i);
    }

    // 销毁
    LinkList_Destroy(list);
    
    system("pause");

    return 0;
}

转载于:https://www.cnblogs.com/ifpelset/articles/4490526.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值