第六天2017/04/11(2:Linux内核链表Demo、顺序表、链表的开发与设计)

//结构体相关的高级话题

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
//定义一个结构体,就相当于各个变量的偏移量也定下来了
struct student
{
    char name[32];  //32个字节
    int age;        //4个字节
    char *na;       //4个字节
};

int main()
{
    struct student s = {"Mr.right" , 24 , "Victory"};
    struct student *p = &s;

    p = p+1;
    p = 0; //p = p - p;  //此时 p 相当于 ((struct student *)0)

    int i = (int )(&(p->name));  //0     int i = (int)(&(((struct student *)0)->name))
    int j = (int )(&(p->age));   //32    int j = (int)(&(((struct student *)0)->age))
    int k = (int )(&(p->na));    //36    int k = (int)(&(((struct student *)0)->na))

    int m = (int)&(((struct student *)0)->name);

//把0地址空间进行类型转换,转换为struct student *的结构体指针;此处 
//再指向结构体中的age; 此处->是一个寻址操作,就是计算age的地址在哪里,没有往age所指向的内存空间读写数据
    //寻址操作对CPU来讲,只不过是一个+-*/操作
//再取地址 ; 
//在把地址转换成十进制 

}
==================================================================================

//【疑问】为什么讲上面的知识:(int)&(((struct student *)0)->age)?
//【答】是为了引出“Linux内核链表了解”!

Linux内核链表了解:
//不是链表包含业务结点
//而是业务结点包含链表

//如何从链表结点的位置找到业务结点的位置呢?

#define offsetof(TYPE,MEMBER)  ((size_t)&((TYPE*)0)->MEMBER)
//求出MEMBER相对于TYPE结构体的偏移量offset

#define container_of(ptr,type,member)  (type*)((char*)ptr - offsetof(type,member))
//求整个结构体的偏移量

下图是Linux内核链表的示意图:可以通过链表结点,根据偏移量offset找到
业务结点的起始地址,对业务结点进行操作。
这里写图片描述

这里写图片描述

这里写图片描述

============================================================================

上述图简单介绍了公司的业务数据的设计,代码如下:
实现:让业务结点和链表结点进行有效的分离

#include<iostream>
using namespace std;

struct List  //链表结点
{
    struct List *next;
};

struct student  //业务结点(中有链表结点)
{
    //数据元素
    int age;
    char name[100];

    //链表结点
    struct List node;
};

void insert_node(struct List *pNew,struct List *pHead)  //插入链表结点
//注解:不用插入业务结点,实质上只要插入链表结点就可以(因为可以通过链表结点找到业务结点,并对业务结点进行访问)
{
    pNew->next = pHead->next; //此时用的是头插法,打印时,输出结果是逆序的
    pHead->next = pNew;
}

void printf_age(struct List *pHead)  //打印业务结点
//就像上面说的那样,遍历链表结点,通过链表结点找到业务结点的入口,并对业务结点的数据元素进行访问
{
    //计算偏移量
    int offset = (int)&(((struct student*)0)->node);
    //找到每一个结点的指针
    struct List *pCur = pHead->next;
    while(pCur)
    {
        struct student* pCur_stu = (struct student*)((char*)pCur - offset);
        cout<<pCur_stu->age<<endl;
        pCur = pCur->next;
    }
}
int main()
{
    struct List pHead;  //定义一个链表头结点
    pHead.next = NULL;

    struct student a,b,c,d;
    a.age = 20;
    b.age = 21;
    c.age = 22;
    d.age = 23;

    insert_node(&a.node,&pHead);  //把链表结点插入到链表结点的头结点上
    insert_node(&b.node,&pHead);
    insert_node(&c.node,&pHead);
    insert_node(&d.node,&pHead);

    printf_age(&pHead);  //打印链表结点

    return 0;
}

实质上可以进行“投机取巧,即永远把链表结点放在业务结点的第一个位置,此时:链表结点相对于业务结点的偏移量offset为0.

struct List  //链表结点
{
    struct List *next;
};

struct student  //业务结点(中有链表结点)
{
    //链表结点
    struct List node;

    //数据元素
    int age;
    char name[100];
};


1、企业级财富库线性表之单链表开发和设计】
//linklist.h函数声明
#ifndef _MYLINKLIST_H_
#define _MYLINKLIST_H_

typedef void LinkList;

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

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
=========================================================================
//linklist.cpp函数实现
#include "stdlib.h"
#include "stdio.h"
#include "string.h"

#include "linklist.h"

typedef struct _tag_LinkList
{
    LinkListNode header;
    int length;
}TLinkList;

LinkList* LinkList_Create()
{
    TLinkList *tList = (TLinkList *)malloc(sizeof(TLinkList));
    if (tList == NULL)
    {
        return NULL;
    }
    tList->header.next = NULL;
    tList->length = 0;
    return tList;
}

void LinkList_Destroy(LinkList* list)
{
    if (list != NULL)
    {
        free(list);
    }
    return ;
}

void LinkList_Clear(LinkList* list)
{
    TLinkList *tList = (TLinkList *)list;
    if (tList == NULL)
    {
        return ;
    }
    tList->length = 0;
    tList->header.next = NULL;
    return ;
}

int LinkList_Length(LinkList* list)
{
    TLinkList *tList = (TLinkList *)list;
    if (tList == NULL)
    {
        return -1;
    }
    return tList->length;
}

int LinkList_Insert(LinkList* list, LinkListNode* pNew, int pos)
{//将业务结点s中的s.node元素插入到单链表中
    int i = 0;
    TLinkList  *tList = (TLinkList *)list;
    LinkListNode  *current = NULL;

    if (tList == NULL || pNew == NULL || pos<0)
    {
        return -1;
    }
    current = &tList->header; //环境初始化

    for (i=0; (i<pos)&&current->next!=NULL; i++ ) //寻找插入位置
    {
        current = current->next;
    }
//插入新结点pNew
    pNew->next = current->next;
    current->next = pNew;
    tList->length ++;

    return 0;
}

LinkListNode* LinkList_Get(LinkList* list, int pos)
{
    int i = 0;
    TLinkList  *tList = (TLinkList *)list;
    LinkListNode  *current = NULL;
    LinkListNode  *ret = NULL;

    if (list==NULL || pos<0 || pos>=tList->length)
    {
        return NULL;
    }

    current = &tList->header;
    for (i=0; i<pos; i++)
    {
        current = current->next;
    }
    ret = current->next;

    return ret;
}

LinkListNode* LinkList_Delete(LinkList* list, int pos)
{
    int i = 0;
    TLinkList  *tList = (TLinkList *)list;
    LinkListNode  *current = NULL;
    LinkListNode  *ret = NULL;

    if (list==NULL || pos<0 || pos>=tList->length)
    {
        return NULL;
    }
    //没有初始化环境
    current = &tList->header;
    for (i=0; i<pos; i++)
    {
        current = current->next;
    }
    ret = current->next;

    current->next = ret->next;
    tList->length --;
    return ret;
}
=========================================================================
//main.cpp测试程序
#include "linklist.h"
#include <iostream>
using namespace std;

struct Student
{
    LinkListNode node;  //Linux内核原理:业务结点中有链表结点
    char name[100];
    int age;
};

void print_LinkList(void* list)  //遍历打印链表
{
    for (int i=0; i<LinkList_Length(list); i++)
    {
        struct Student *tmp = (struct Student*)LinkList_Get(list, i);
        printf("name: %s , age: %d\n", tmp->name,tmp->age);
    }
}

int main()
{
    Student s1;  strcpy(s1.name,"Tom");  s1.age = 20;
    Student s2;  strcpy(s2.name,"Tim");  s2.age = 21;
    Student s3;  strcpy(s3.name,"Kim");  s3.age = 22;

    LinkList* list = list = LinkList_Create();  

/************************************************************************/
//case1:
    LinkList_Insert(list,&s1.node,0); //把s1中的链表结点s1.node结点插入到链表list
    LinkList_Insert(list,&s2.node,0); //把s2中的链表结点s2.node结点插入到链表list
    LinkList_Insert(list,&s3.node,0); //把s3中的链表结点s3.node结点插入到链表list

    //LinkList_Insert(list,(LinkListNode*)(&s1.node),0);
    //LinkList_Insert(list,(LinkListNode*)(&s2.node),0);
    //LinkList_Insert(list,(LinkListNode*)(&s3.node),0);
//case2:
    //LinkList_Insert(list,(LinkListNode*)(&s1),0);
    //LinkList_Insert(list,(LinkListNode*)(&s2),0);
    //LinkList_Insert(list,(LinkListNode*)(&s3),0);

        print_LinkList(list);
/************************************************************************/

    cout<<"删除结点"<<endl;
    LinkList_Delete(list,1);
    print_LinkList(list);

}
/************************************************************************/
/************************************************************************/2、企业级财富库线性表之顺序存储开发和设计】
【核心问题】
    业务数据 和 链表算法(底层库)是如何分离的?
//seqlist.h:函数声明
#ifndef  __MY_SEQLIST_H__ 
#define __MY_SEQLIST_H__

typedef void SeqList;  
typedef void SeqListNode;

//疑问:为什么传入的形参类型、返回的类型为void* ?
//答:底层不想让别人知道我是什么结构的,也没有必要让别人知道

SeqList* SeqList_Create(int capacity); //创建容量为capacity的顺序线性表
void SeqList_Destroy(SeqList* list);  //释放线性表list
void SeqList_Clear(SeqList* list);    //清空线性表list
int SeqList_Length(SeqList* list);
int SeqList_Capacity(SeqList* list);
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos);
SeqListNode* SeqList_Get(SeqList* list, int pos);
SeqListNode* SeqList_Delete(SeqList* list, int pos);
int for_each(void (*CALLBACK_print)(void*),void* list); //回调函数循环遍历
#endif  

//void* SeqList_Create(int capacity);
//void SeqList_Destroy(void* list);
//void SeqList_Clear(void* list);
//int SeqList_Length(void* list);
//int SeqList_Capacity(void* list);
//int SeqList_Insert(void* list, void* node, int pos);
//void* SeqList_Get(void* list, int pos);
//void* SeqList_Delete(void* list, int pos);

===============================================================================
//seqlist.cpp:函数实现
#include "seqlist.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"

typedef struct _tag_SeqList
{
    int capacity;  //sizeof(数组),数组实际占有的内存大小
    int length;    //strlen(数组),数组中存放着几个数据
    unsigned int *node ; //数组的头指针
}TSeqList;

//typdef的意思 把void 重新命名成SeqList

/*
void * SeqList_Create2(int capacity)  //分配两次内存,恶心!
{
    TSeqList *ret = NULL;
    ret = (TSeqList *)malloc(sizeof(TSeqList));
    if (ret == NULL)
    {
        return NULL;
    }
    ret->capacity = capacity;
    ret->node = (unsigned int *)malloc(sizeof(unsigned int ) * capacity);
    if (ret->node == NULL)
    {
        return NULL;
    }
    ret->length = 0;
    return ret;
}
*/

void * SeqList_Create(int capacity) //创建一个长度为capacity的数组,数组的数据类型是unsigned int
{
    TSeqList *ret = NULL;
    if (capacity <= 0)
    {
        return NULL;
    }
    ret = (TSeqList *)malloc(sizeof(TSeqList) + sizeof(unsigned int ) * capacity );//一次性全部分配内存
    if (ret == NULL)
    {
        return NULL;
    }
    ret->capacity = capacity;   
    ret->length = 0;
    ret->node = (unsigned int *)(ret + 1);

    return ret;
}

void SeqList_Destroy(SeqList* list)
{
    if (list == NULL)
    {
        return ;
    }
    free(list);
    return ;
}

void SeqList_Clear(SeqList* list) //不是释放内存,是直接把长度设为0
{
    TSeqList *tlist = NULL;
    if (list == NULL)
    {
        return ;
    }
    tlist = (TSeqList *)list;

    tlist->length = 0;//直接把长度设为0
    return ;
}

int SeqList_Length(SeqList* list)
{
    TSeqList *tlist = (TSeqList *)list;
    if (list == NULL)
    {
        return -1;
    }
    return tlist->length;
}

int SeqList_Capacity(SeqList* list)  
{
    TSeqList *tlist = (TSeqList *)list;
    if (list == NULL)
    {
        return -1;
    }
    return tlist->capacity;
}
//注解:实际位置和下标位置总是相差1
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos)  //插入位置:length+1>=pos>=1
{
    if(list == NULL||node == NULL)
        return -1;
    TSeqList *tlist = (TSeqList*)list;
//capacity空间不够
    if(tlist->length >= tlist->capacity) 
        return -2;
//容错 //插入位置length+1>=pos>=1
    if(pos > tlist->length+1)
    {
        pos = tlist->length;
    }
    if(pos < 1)
    {
        pos = 1;
    }
//插入操作
    int i = tlist->length-1; //最后一个有效元素的位置
    while(i>=pos-1) //循环后移
    {
        tlist->node[i+1] = tlist->node[i];
        i--;
    }
    tlist->node[pos-1] = (unsigned int)node; //插入
    tlist->length++;
    return 0;
}


SeqListNode* SeqList_Get(SeqList* list, int pos) //查找位置:length>=pos>=1
{
    TSeqList *tlist = (TSeqList *)list;

    if (list== NULL || pos<1 || pos>tlist->length)
    {
        return NULL;
    }
    return (SeqListNode*)tlist->node[pos-1];  
}

SeqListNode* SeqList_Delete(SeqList* list, int pos) //删除位置:length>=pos>=1
{
    int i = 0;
    TSeqList *tlist = (TSeqList *)list;
    SeqListNode* ret = NULL;
    if (list == NULL || pos<1 || pos>tlist->length)
    {
        return NULL;
    }
//缓存要删除的结点
    ret = (SeqListNode*)tlist->node[pos-1];
//对链表元素值循环前移
    i = pos-1;
    while(i<=tlist->length-1)
    {
        tlist->node[i] = tlist->node[i+1];
        i++;
    }
//删除后,长度-1
    tlist->length --;
    return ret;
}

int for_each(void (*CALLBACK_print)(void*),void* list)
{
    if(list == NULL)
        return -1;
    (*CALLBACK_print)(list);
    return 0;
}
===============================================================================
//线性表顺序存储测试.cpp:测试代码
#include "seqlist.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"

typedef struct _Teacher  //业务结点
{
    char name[64];
    int age ;
}Teacher;

void CALLBACK_print(void* list) //循环遍历的回调函数
{
    printf("循环遍历:\n");
    for (int i=1; i<=SeqList_Length(list); i++)
    {
        Teacher *tmp = (Teacher *)SeqList_Get(list, i);
        printf("name:%s  ,  age:%d \n", tmp->name,tmp->age);
    }
}

void main()
{
//创建业务数据,并初始化
    Teacher t1 = {"Kobe",20};
    Teacher t2 = {"James",19};
    Teacher t3 = {"Curry",16};
//环境准备
    int ret = 0, i = 0;
    SeqList* list = NULL;
//创建线性表
    list = SeqList_Create(10);
    //仔细思考:业务数据 和 链表算法(底层库)是如何分离的。。。。。。
    //业务数据结点的管理(内存的生命周期)甩给了上层应用(业务模型)
//插入
    ret = SeqList_Insert(list, (SeqListNode*)&t1, 1);
    ret = SeqList_Insert(list, (SeqListNode*)&t2, 1);
    ret = SeqList_Insert(list, (SeqListNode*)&t3, 1);
//循环遍历
    for_each(CALLBACK_print,list); 
//删除    
    SeqList_Delete(list, 2);
    for_each(CALLBACK_print,list); 
//销毁线性表
    SeqList_Destroy(list);
    system("pause");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值