C language Object-Oriented Programming (V): single-chain table implementation

Source: Internet
Author: User

We have introduced how to introduce some features of object-oriented language to object-oriented programming in C. Starting from this article, we will use the techniques mentioned above to implement several examples in succession, finally, a basic http server implementation (using libevent) is provided ). In this article, we implement a common data structure: a single-chain table.

The single-chain table can store any data type and supports basic operations such as adding, deleting, modifying, searching, and inserting. (This article provides the complete code, which may be somewhat long .)

The following is the header file:

#ifndef SLIST_H#define SLIST_H#ifdef __cplusplusextern "C" {#endif#define NODE_T(ptr, type) ((type*)ptr)struct slist_node {    struct slist_node * next;};typedef void (*list_op_free_node)(struct slist_node *node);/* * return 0 on hit key, else return none zero */typedef int (*list_op_key_hit_test)(struct slist_node *node, void *key);struct single_list {    /* all the members must not be changed manually by callee */    struct slist_node * head;    struct slist_node * tail;    int size; /* length of the list, do not change it manually*/    /* free method to delete the node     */    void (*free_node)(struct slist_node *node);    /*     * should be set by callee, used to locate node by key(*_by_key() method)     * return 0 on hit key, else return none zero     */    int (*key_hit_test)(struct slist_node *node, void *key);    struct single_list *(*add)(struct single_list * list, struct slist_node * node);    struct single_list *(*insert)(struct single_list * list, int pos, struct slist_node *node);    /* NOTE: the original node at the pos will be freed by free_node */    struct single_list *(*replace)(struct single_list *list, int pos, struct slist_node *node);    struct slist_node *(*find_by_key)(struct single_list *, void * key);    struct slist_node *(*first)(struct single_list* list);    struct slist_node *(*last)(struct single_list* list);    struct slist_node *(*at)(struct single_list * list, int pos);    struct slist_node *(*take_at)(struct single_list * list, int pos);    struct slist_node *(*take_by_key)(struct single_list * list, void *key);    struct single_list *(*remove)(struct single_list * list, struct slist_node * node);    struct single_list *(*remove_at)(struct single_list *list, int pos);    struct single_list *(*remove_by_key)(struct single_list *list, void *key);    int (*length)(struct single_list * list);    void (*clear)(struct single_list * list);    void (*deletor)(struct single_list *list);};struct single_list * new_single_list(list_op_free_node op_free, list_op_key_hit_test op_cmp);#ifdef __cplusplus}#endif#endif // SLIST_H

The struct single_list class follows the basic principles described above and is not described in detail. There are several points to mention:

We have defined slist_node as the base class of the linked list node. All user-defined nodes must inherit from slist_node. To support node release, we introduce a callback function list_op_free_node, this callback needs to be passed in when creating a linked list to support searching. another callback function list_op_key_hit_test is introduced.

Now, let's look at the implementation file:

#include "slist.h"#include 
 
  static struct single_list * _add_node(struct single_list *list, struct slist_node *node){    if(list->tail)    {        list->tail->next = node;        node->next = 0;        list->tail = node;        list->size++;    }    else    {        list->head = node;        list->tail = node;        node->next = 0;        list->size = 1;    }    return list;}static struct single_list * _insert_node(struct single_list * list, int pos, struct slist_node *node){    if(pos < list->size)    {        int i = 0;        struct slist_node * p = list->head;        struct slist_node * prev = list->head;        for(; i < pos; i++)        {            prev = p;            p = p->next;        }        if(p == list->head)        {            /* insert at head */            node->next = list->head;            list->head = node;        }        else        {            prev->next = node;            node->next = p;        }        if(node->next == 0) list->tail = node;        list->size++;    }    else    {        list->add(list, node);    }    return list;}static struct single_list * _replace(struct single_list * list, int pos, struct slist_node *node){    if(pos < list->size)    {        int i = 0;        struct slist_node * p = list->head;        struct slist_node * prev = list->head;        for(; i < pos; i++)        {            prev = p;            p = p->next;        }        if(p == list->head)        {            /* replace at head */            node->next = list->head->next;            list->head = node;        }        else        {            prev->next = node;            node->next = p->next;        }        if(node->next == 0) list->tail = node;        if(list->free_node) list->free_node(p);        else free(p);    }    return list;}static struct slist_node * _find_by_key(struct single_list *list, void * key){    if(list->key_hit_test)    {        struct slist_node * p = list->head;        while(p)        {            if(list->key_hit_test(p, key) == 0) return p;            p = p->next;        }    }    return 0;}static struct slist_node *_first_of(struct single_list* list){    return list->head;}static struct slist_node *_last_of(struct single_list* list){    return list->tail;}static struct slist_node *_node_at(struct single_list * list, int pos){    if(pos < list->size)    {        int i = 0;        struct slist_node * p = list->head;        for(; i < pos; i++)        {            p = p->next;        }        return p;    }    return 0;}static struct slist_node * _take_at(struct single_list * list, int pos){    if(pos < list->size)    {        int i = 0;        struct slist_node * p = list->head;        struct slist_node * prev = p;        for(; i < pos ; i++)        {            prev = p;            p = p->next;        }        if(p == list->head)        {            list->head = p->next;            if(list->head == 0) list->tail = 0;        }        else if(p == list->tail)        {            list->tail = prev;            prev->next = 0;        }        else        {            prev->next = p->next;        }        list->size--;        p->next = 0;        return p;    }    return 0;}static struct slist_node * _take_by_key(struct single_list * list, void *key){    if(list->key_hit_test)    {        struct slist_node * p = list->head;        struct slist_node * prev = p;        while(p)        {            if(list->key_hit_test(p, key) == 0) break;            prev = p;            p = p->next;        }        if(p)        {            if(p == list->head)            {                list->head = p->next;                if(list->head == 0) list->tail = 0;            }            else if(p == list->tail)            {                list->tail = prev;                prev->next = 0;            }            else            {                prev->next = p->next;            }            list->size--;            p->next = 0;            return p;        }    }    return 0;}static struct single_list *_remove_node(struct single_list * list, struct slist_node * node){    struct slist_node * p = list->head;    struct slist_node * prev = p;    while(p)    {        if(p == node) break;        prev = p;        p = p->next;    }    if(p)    {        if(p == list->head)        {            list->head = list->head->next;            if(list->head == 0) list->tail = 0;        }        else if(p == list->tail)        {            prev->next = 0;            list->tail = prev;        }        else        {            prev->next = p->next;        }        if(list->free_node) list->free_node(p);        else free(p);        list->size--;    }    return list;}static struct single_list *_remove_at(struct single_list *list, int pos){    if(pos < list->size)    {        int i = 0;        struct slist_node * p = list->head;        struct slist_node * prev = p;        for(; i < pos ; i++)        {            prev = p;            p = p->next;        }        if(p == list->head)        {            list->head = p->next;            if(list->head == 0) list->tail = 0;        }        else if(p == list->tail)        {            list->tail = prev;            prev->next = 0;        }        else        {            prev->next = p->next;        }        if(list->free_node) list->free_node(p);        else free(p);        list->size--;    }    return list;}static struct single_list *_remove_by_key(struct single_list *list, void *key){    if(list->key_hit_test)    {        struct slist_node * p = list->head;        struct slist_node * prev = p;        while(p)        {            if(list->key_hit_test(p, key) == 0) break;            prev = p;            p = p->next;        }        if(p)        {            if(p == list->head)            {                list->head = list->head->next;                if(list->head == 0) list->tail = 0;            }            else if(p == list->tail)            {                prev->next = 0;                list->tail = prev;            }            else            {                prev->next = p->next;            }            if(list->free_node) list->free_node(p);            else free(p);            list->size--;        }    }    return list;}static int _length_of(struct single_list * list){    return list->size;}static void _clear_list(struct single_list * list){    struct slist_node * p = list->head;    struct slist_node * p2;    while(p)    {        p2 = p;        p = p->next;        if(list->free_node) list->free_node(p2);        else free(p2);    }    list->head = 0;    list->tail = 0;    list->size = 0;}static void _delete_single_list(struct single_list *list){    list->clear(list);    free(list);}struct single_list * new_single_list(list_op_free_node op_free, list_op_key_hit_test op_cmp){    struct single_list *list = (struct single_list *)malloc(sizeof(struct single_list));    list->head = 0;    list->tail = 0;    list->size = 0;    list->free_node = op_free;    list->key_hit_test = op_cmp;    list->add = _add_node;    list->insert = _insert_node;    list->replace = _replace;    list->find_by_key = _find_by_key;    list->first = _first_of;    list->last = _last_of;    list->at = _node_at;    list->take_at = _take_at;    list->take_by_key = _take_by_key;    list->remove = _remove_node;    list->remove_at = _remove_at;    list->remove_by_key = _remove_by_key;    list->length = _length_of;    list->clear = _clear_list;    list->deletor = _delete_single_list;    return list;}
 

The above code is not described in detail. The following is the test code:

/* call 1 or N arguments function of struct */#define ST_CALL(THIS,func,args...) ((THIS)->func(THIS,args))/* call none-arguments function of struct */#define ST_CALL_0(THIS,func) ((THIS)->func(THIS))struct int_node {    struct slist_node node;    int id;};struct string_node {    struct slist_node node;    char name[16];};static int int_free_flag = 0;static void _int_child_free(struct slist_node *node){    free(node);    if(!int_free_flag)    {        int_free_flag = 1;        printf("int node free\n");    }}static int _int_slist_hittest(struct slist_node * node, void *key){    struct int_node * inode = NODE_T(node, struct int_node);    int ikey = (int)key;    return (inode->id == ikey ? 0 : 1);}static int string_free_flag = 0;static void _string_child_free(struct slist_node *node){    free(node);    if(!string_free_flag)    {        string_free_flag = 1;        printf("string node free\n");    }}static int _string_slist_hittest(struct slist_node * node, void *key){    struct string_node * sn = (struct string_node*)node;    return strcmp(sn->name, (char*)key);}void int_slist_test(){    struct single_list * list = new_single_list(_int_child_free, _int_slist_hittest);    struct int_node * node = 0;    struct slist_node * bn = 0;    int i = 0;    printf("create list && nodes:\n");    for(; i < 100; i++)    {        node = (struct int_node*)malloc(sizeof(struct int_node));        node->id = i;        if(i%10)        {            list->add(list, node);        }        else        {            list->insert(list, 1, node);        }    }    printf("create 100 nodes end\n----\n");    printf("first is : %d, last is: %d\n----\n",           NODE_T( ST_CALL_0(list, first), struct int_node )->id,           NODE_T( ST_CALL_0(list, last ), struct int_node )->id);    assert(list->size == 100);    printf("list traverse:\n");    for(i = 0; i < 100; i++)    {        if(i%10 == 0) printf("\n");        bn = list->at(list, i);        node = NODE_T(bn, struct int_node);        printf(" %d", node->id);    }    printf("\n-----\n");    printf("find by key test, key=42:\n");    bn = list->find_by_key(list, (void*)42);    assert(bn != 0);    node = NODE_T(bn, struct int_node);    printf("find node(key=42), %d\n------\n", node->id);    printf("remove node test, remove the 10th node:\n");    bn = list->at(list, 10);    node = NODE_T(bn, struct int_node);    printf("  node 10 is: %d\n", node->id);    printf("  now remove node 10\n");    list->remove_at(list, 10);    printf(" node 10 was removed, check node 10 again:\n");    bn = list->at(list, 10);    node = NODE_T(bn, struct int_node);    printf("  now node 10 is: %d\n------\n", node->id);    printf("replace test, replace node 12 with id 1200:\n");    bn = list->at(list, 12);    node = NODE_T(bn, struct int_node);    printf("  now node 12 is : %d\n", node->id);    node = (struct int_node*)malloc(sizeof(struct int_node));    node->id = 1200;    list->replace(list, 12, node);    bn = list->at(list, 12);    node = NODE_T(bn, struct int_node);    printf("  replaced, now node 12 is : %d\n----\n", node->id);    printf("test remove:\n");    ST_CALL(list, remove, bn);    bn = ST_CALL(list, find_by_key, (void*)1200);    assert(bn == 0);    printf("test remove ok\n----\n");    printf("test remove_by_key(90):\n");    ST_CALL(list, remove_by_key, (void*)90);    bn = ST_CALL(list, find_by_key, (void*)90);    assert(bn == 0);    printf("test remove_by_key(90) end\n----\n");    printf("test take_at(80):\n");    bn = ST_CALL(list, take_at, 80);    printf("  node 80 is: %d\n", NODE_T(bn, struct int_node)->id);    free(bn);    printf("test take_at(80) end\n");    int_free_flag = 0;    printf("delete list && nodes:\n");    list->deletor(list);    printf("delete list && nodes end\n");    printf("\n test add/insert/remove/delete/find_by_key/replace...\n");}void string_slist_test(){    struct single_list * list = new_single_list(_string_child_free, _string_slist_hittest);}void slist_test(){    int_slist_test();    string_slist_test();}

The test code mainly demonstrates:

Custom linked list node type definition release callback definition how to use the hit test callback for searching to create a linked list (add, remove, take, find, insert, etc)

I believe that the use of a single-chain table is no longer a problem.

Based on a single-chain table, you can further implement many data structures, such as tree (sibling Notation), such as the key-value linked list. Next, we will choose a machine based on the needs of the example.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.