zoukankan      html  css  js  c++  java
  • 数据结构-有头双向循环链表2(封装)

    list.c

    /*
     *把数据结构封装
     * 支持变长结构体:在网络传输的过程,包的大小不固定的情况适用
     *实现create , delete ,insert , find , fetch等功能
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "list.h"
    
    
    
    //双向循环链表普通节点
    struct llist_node_st
    {
        struct llist_node_st * prev ;//前驱
        struct llist_node_st * next ;//后继
        char data[1] ;
    };
    
    //定义头节点LLIST类型,链表的起始地址
    struct llist_head_st
    {
        int size ;
        struct llist_node_st head ;
    };
    
    /* ****************************
     * 功能:创建带头节点链表
     * 参数:initsize(变参的长度)
     * 返回:无
     * ***************************/
    struct llist_head_st * llist_create(int initsize)
    {
        //1.创建
        struct llist_head_st * new ;
        new = malloc(sizeof(*new));
        if(new == NULL)
            return NULL;
        //2.初始化
        new->size = initsize ;
        new->head.prev = &new->head ;
        new->head.next = &new->head ;
        return new ;
    }
    
    /* *******************************************************
     * 功能:以mode的方式向链表ptr中插入数据data
     * 参数:ptr:链表
     *       data:要插入的数据
     *       mode:插入的方式:FORWARD(头插) BACKWARD(尾插)
     * 返回:-1:内存申请失败,-2:方式不对,0:返回正确
     * *******************************************************/
    int llist_insert(LLIST *p , const void * data , int mode )
    {
        //1.创建新节点并分配空间
        struct llist_node_st *newnode ;
        struct llist_head_st *ptr = p;
        newnode = malloc(sizeof(*newnode) + ptr->size );//申请空间就是结构体大小+头节点里的size元素
        if(newnode == NULL)
            return -1 ;
        //2.将data内容复制到新节点的数据中
        memcpy(newnode->data,data,ptr->size);
        //3.判断插入方式并插入
        if(mode == LLIST_FORWARD)
        {
            newnode->prev = &ptr->head ;
            newnode->next = ptr->head.next ;
        }
        else if(mode == LLIST_BACKWARD)
        {
            newnode->next = &ptr->head ;
            newnode->prev = ptr->head.prev ;
        }
        else
            return -3 ;
        printf("insert
    ");
        newnode->prev->next = newnode ;
        newnode->next->prev = newnode ;
        return 0 ;
    }
    
    /* *******************************************************
     * 功能:以op的方式遍历链表ptr
     * 参数:ptr:链表
     *       op:遍历方式(main.c中使用print_s打印的方式遍历)
     * 返回:无
     * *******************************************************/
    void llist_travel(LLIST *p ,llist_op *op )
    {
        //1.创建一个节点
        struct llist_node_st *cur ;
        struct llist_head_st *ptr = p;
        //2.cur节点从头的后继开始;以不循环到头节点为止 ;向后移动
        for (cur = ptr->head.next ; cur != &ptr->head ;cur = cur->next)
        {
            //3.将每个节点的data返回给用户
            op(cur->data) ;
        }
    }
    
    /* ******************
     * 功能:销毁链表ptr
     * 参数:ptr:链表
     * 返回:无
     * *****************/
    void llist_destroy(LLIST *p)
    {
        //1.创建当前节点以及当前节点的下一个节点
        struct llist_node_st *cur ; 
        struct llist_node_st *next ;
        struct llist_head_st *ptr = p;
        //2.当前节点从头的后继开始;并且不等于头节点地址 ;指向下一个节点
        for(cur = ptr->head.next ; cur != &ptr->head ; cur = next)
        {
            next = cur->next;
            //3.释放空间
            free(cur);
        }
        //4.释放头节点
        free(ptr);
    }
    
    
    /* *******************************************************
     * 功能:从链表ptr,按照cmp的比较方式,查找key  只能内部调用,非接口函数
     * 参数:ptr:链表
     *       key:查找内容
     *       cmp:比较函数
     * 返回:返回find符合的节点指针,没有符合返回NULL
     * *******************************************************/
    static struct llist_node_st  * find_(struct llist_head_st *ptr ,const void *key ,llist_cmp *cmp)
    {
        //1.创建节点
        struct llist_node_st *cur ;
        //2.当前节点从头的后继开始;并且不等于头节点地址 ;指向下一个节点
        for(cur = ptr->head.next ;cur != &ptr->head ; cur = cur->next)
        {
            //3.如果匹配跳出循环,并返回当前节点的指针
            if(cmp(key , cur->data) == 0 )
                break;
        }
        return cur ;
    }
    
    /* *******************************************************
     * 功能:从链表ptr,按照cmp的比较方式,查找key
     * 参数:ptr:链表
     *         key:查找内容
     *       cmp:比较函数
     * 返回:返回相应节点的数据起始地址,否则返回NULL
     * *******************************************************/
    void * llist_find(LLIST *p,const void *key ,llist_cmp *cmp)
    {
        //1.创建节点
        struct llist_node_st *node ;
        struct llist_head_st *ptr= p;
        //2.调用find_函数得到匹配的节点
        node = find_(ptr , key ,cmp);
        //3.没有找到匹配节点,返回空NULL
        if(node == &ptr->head)//头节点--没有找到
            return NULL;
        //4.找到节点返回节点的数据的起始地址
        return node->data;
    }
    
    /* *******************************************************
     * 功能:从链表ptr,按照cmp的比较方式,删除key的节点
     * 参数:ptr:链表
     *         key:查找内容
     *       cmp:比较函数
     * 返回:成功返回0,否则返回-1
     * *******************************************************/
    int llist_delete(LLIST *p, const void *key,llist_cmp *cmp)
    {
        //1.创建节点
        struct llist_node_st *node ;
        struct llist_head_st *ptr = p ;
        //2.找到匹配的节点,没找到返回-1
        node = find_(ptr, key ,cmp );
        if(node == &ptr->head)
            return -1 ;
        //3.更改前驱节点的后继、后继节点的前驱
        node->prev->next = node->next ;
        node->next->prev = node->prev ;
        //4.释放节点,正确返回0
        free(node) ;
        return 0 ;
    }
    
    /* *******************************************************
     * 功能:从链表ptr,按照cmp的比较方式,删除key,并将删除节点回填data
     * 参数:ptr:链表
     *         key:查找内容
     *       cmp:比较函数
     * 返回:返回相应节点的数据起始地址,否则返回NULL
     * *******************************************************/
    int llist_fetch(LLIST *p , const void *key ,llist_cmp *cmp , void *data)
    {
        //1.创建节点
        struct llist_node_st *node ;
        struct llist_head_st *ptr = p;
        //2.找到匹配的节点,没有返回-1
        node = find_(ptr , key ,cmp);
        if(node == &ptr->head)
            return -1 ;
        //3.修改前驱节点的后继、修改后继节点的前驱
        node->prev->next = node->next ;
        node->next->prev = node->prev ;
        //4.将要删除的节点回填
        if(data != NULL)
        {
            memcpy(data , node->data , ptr->size);
        }
        //5.释放节点
        free(node);
        return 0 ;
    }
    View Code

    list.h

    #ifndef LIST_H__
    #define    LIST_H__
    
    //插入模式
    #define    LLIST_FORWARD    1 
    #define    LLIST_BACKWARD    2
    
    typedef void LLIST ;
    //回调函数
    typedef void llist_op(const void *) ;
    typedef int llist_cmp(const void *,const void *);
    
    void * llist_find(LLIST *ptr ,const void *key ,llist_cmp *);
    int llist_delete(LLIST *ptr,const void *key , llist_cmp * );
    void llist_travel(LLIST *ptr ,llist_op *op );
    int llist_fetch(LLIST *ptr , const void *key ,llist_cmp *cmp , void *data);
    void llist_destroy(LLIST *);
    #endif
    View Code

    main.c

    #include <stdlib.h>
    #include <stdio.h>
    
    #include "list.h"
    
    #define    NAMESIZE    32
    
    //定义数据结构体
    struct score_st
    {
        int id ;
        char name[NAMESIZE] ;
        int math ;
        int chinese ;
    };
    //打印函数
    static void print_s(const void *record)
    {
        const struct score_st *r = record ;
        printf("%d %s %d %d 
    ",r->id , r->name , r->math , r->chinese);
    }
    //id比较函数
    static int id_cmp(const void * key ,const void *record)
    {
        const int * k = key ;
        const struct score_st *r = record ;
        return (*k -r->id);
    
    }
    //name比较函数
    static int name_cmp(const void *key ,const void *record)
    {
        const char * k = key ;
        const struct score_st *r = record ;
        return(strcmp(k,r->name));
    
    }
    
    int main()
    {
        //1.定义节点
        LLIST *handler;
        //2.定义数据结构
        struct score_st tmp ;
        //3.定义接收的数据结构指针
        struct score_st *data = NULL;
        //4.变量i以及返回值ret
        int i ,ret ;
        //5.查找id 以及name
        int id = 3 ;
        char *del_name = "std6";
    
        /************************************/
        //1.创建节点:成功返回节点指针,失败返回NULL;参数为初始数据长度initsize
        handler = llist_create (sizeof(struct score_st));
        if(handler == NULL)
            exit(1);
        printf("%d",__LINE__);    
        //2.链表数据赋值:使用insert方式
        for(i = 0 ; i < 7 ; i++)
        {
            tmp.id = i ;
            snprintf(tmp.name,NAMESIZE ,"std%d",i);
            tmp.math = rand()%100;
            tmp.chinese = rand()%100 ;
            ret = llist_insert(handler,&tmp,2);
            if(ret)
                exit(1);
        }
        //3.链表遍历
        llist_travel(handler,print_s);
        printf("
    
    ");
        //4.链表数据查找
        data = llist_find(handler , &id ,id_cmp);
        if(data == NULL)
            printf("can not find 
    ");
        else
            print_s(data);
    
        printf("
    
    ");
        //5.链表数据删除
        ret = llist_delete(handler ,del_name  ,name_cmp);
        if(ret)
            printf("delete failed 
    ");
        //6.链表遍历
        llist_travel(handler,print_s);
        //7.链表销毁
        llist_destroy(handler);
        exit(0);
    }
    View Code

    Makefie

    all :main
    main:list.o main.o
        $(CC) $^ -o $@
    clean:
        rm *.o main -rf
    View Code
  • 相关阅读:
    MinGW-编译器
    Enum , Enum Class ?
    C++编译器之间的不同性能
    交叉验证
    经验风险最小化-结构风险最小化
    图像卷积
    pytorch官网上两个例程
    ORB feature(O for orientation)
    Catalan数
    无责任共享 Coursera、Udacity 等课程视频(转载)
  • 原文地址:https://www.cnblogs.com/muzihuan/p/5238561.html
Copyright © 2011-2022 走看看