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

    list.h

    #ifndef LIST_H__
    #define LIST_H__
    
    //插入模式
    #define LLIST_FORWARD   1 
    #define LLIST_BACKWARD  2
    
    //回调函数
    typedef void llist_op(const void *) ;
    typedef int llist_cmp(const void *,const void *);
    
    
    //双向循环链表普通节点
    struct llist_node_st
    {
        //void * data ;//放在第一行,需要固定长度,不好操作
        struct llist_node_st * prev ;//前驱
        struct llist_node_st * next ;//后继
        //char data[0];C99才支持长度为0的数组,之前的标准是不支持的,为了方便我们定义char data[1]
        char data[1] ;//变长:data 就是变长数据的首地址:类似占位符
                      //如果char data;->找不到data 的地址
                      //直接可以把头节点的size放到data中,申请llist_node_st + size 的大小
    };
    
    //定义头节点LLIST类型,链表的起始地址
    typedef struct llist_head
    {
        int size ;
        struct llist_node_st head ;
        /*****************
         *封装方法
         ****************/
        int (*insert)(struct llist_head * , const void * data , int mode );
        void *(*find)(struct llist_head * ,const void *key ,llist_cmp *);
        int (*delete)(struct llist_head *,const void *key , llist_cmp * );
        int (*fetch)(struct llist_head * , const void *key ,llist_cmp * , void *data);
        void (*travel)(struct llist_head *,llist_op * );
    }LLIST;
    
    
    LLIST * llist_create(int initsize);
    void llist_destroy(LLIST *);
    #endif
    View Code

    list.c

    /*
     *面向对象的思想
     * 支持变长结构体:在网络传输的过程,包的大小不固定的情况适用
     *实现create , delete ,insert , find , fetch等功能
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "list.h"
    
    /*********************函数声明******************************/
    int llist_insert(LLIST *ptr , const void * data , int mode );
    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);
    
    
    /* ****************************
     * 功能:创建带头节点链表
     * 参数:initsize(变参的长度)
     * 返回:无
     * ***************************/
    LLIST * llist_create(int initsize)
    {
        //1.创建
        LLIST * new ;
        new = malloc(sizeof(*new));
        if(new == NULL)
            return NULL;
        //2.初始化
        new->size = initsize ;
        new->head.prev = &new->head ;
        new->head.next = &new->head ;
        new->insert = llist_insert ;
        new->delete = llist_delete ;
        new->travel = llist_travel ;
        new->find = llist_find ;
        new->fetch = llist_fetch ;
    }
    
    /* *******************************************************
     * 功能:以mode的方式向链表ptr中插入数据data
     * 参数:ptr:链表
     *       data:要插入的数据
     *       mode:插入的方式:FORWARD(头插) BACKWARD(尾插)
     * 返回:-1:内存申请失败,-2:方式不对,0:返回正确
     * *******************************************************/
    int llist_insert(LLIST *ptr , const void * data , int mode )
    {
        //1.创建新节点并分配空间
        struct llist_node_st *newnode ;
        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 -2 ;
        newnode->prev->next = newnode ;
        newnode->next->prev = newnode ;
        return 0 ;
    }
    
    /* *******************************************************
     * 功能:以op的方式遍历链表ptr
     * 参数:ptr:链表
     *       op:遍历方式(main.c中使用print_s打印的方式遍历)
     * 返回:无
     * *******************************************************/
    void llist_travel(LLIST *ptr ,llist_op *op )
    {
        //1.创建一个节点
        struct llist_node_st *cur ;
        //2.cur节点从头的后继开始;以不循环到头节点为止 ;向后移动
        for (cur = ptr->head.next ; cur != &ptr->head ;cur = cur->next)
        {
            //3.将每个节点的data返回给用户
            op(cur->data) ;
        }
    }
    
    /* ******************
     * 功能:销毁链表ptr
     * 参数:ptr:链表
     * 返回:无
     * *****************/
    void llist_destroy(LLIST *ptr)
    {
        //1.创建当前节点以及当前节点的下一个节点
        struct llist_node_st *cur ;
        struct llist_node_st *next ;
        //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_(LLIST * 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 * ptr ,const void *key ,llist_cmp *cmp)
    {
        //1.创建节点
        struct llist_node_st *node ;
        //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 *ptr, const void *key,llist_cmp *cmp)
    {
        //1.创建节点
        struct llist_node_st *node ;
        //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 *ptr , const void *key ,llist_cmp *cmp , void *data)
    {
        //1.创建节点
        struct llist_node_st *node ;
        //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

    create()函数结尾忘记加了return new ;

    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 ;
        //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);
        //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 = handler->insert(handler,&tmp,LLIST_BACKWARD);
            if(ret)
                exit(1);
        }
        //3.链表遍历
        handler->travel(handler,print_s);
        printf("
    
    ");
        //4.链表数据查找
        data = handler->find(handler , &id ,id_cmp);
        if(data == NULL)
            printf("can not find 
    ");
        else
            print_s(data);
    
        printf("
    
    ");
        //5.链表数据删除
        ret = handler->delete(handler ,del_name  ,name_cmp);
        if(ret)
            printf("delete failed 
    ");
        //6.链表遍历
        handler->travel(handler,print_s);
        //7.链表销毁
        llist_destroy(handler);
        exit(0);
    }
    View Code

    Makefile

    all :main
    main:list.o main.o
        $(CC) $^ -o $@
    clean:
        rm *.o main -rf
    View Code
  • 相关阅读:
    android 3dmax
    android 源码
    android 获取 图片 缩略图
    android 导入 3d 场景
    TSQL查询进阶理解SQL SERVER中的分区表
    android 画直接2
    sqlServer 加速
    android 动态壁纸
    sqlServer 2000 唯一 索引
    视频网站
  • 原文地址:https://www.cnblogs.com/muzihuan/p/5238297.html
Copyright © 2011-2022 走看看