C.Interface.And.Implementations—set的實現

1、A set is an  unordered collection of distinct members. 

2、The basic operations on a set are testing  for membership, adding members, and removing members. 

3、Other operations include set union, intersection, difference, and symmetric difference. 


set實現類似於table(key-value系統)的實現,採用類似的“哈希表和鏈表”的底層數據結構。可以參看上一章的內容。


=============================set.h==============================

#ifndef SET_INCLUDED
#define SET_INCLUDED

#define T Set_T
typedef struct T *T;

//exported functions
extern T      Set_new   (int hint,
    int cmp(const void *x, const void *y),
    unsigned hash(const void *x));

extern void   Set_free  (T *set);
extern int    Set_length(T set);
extern int    Set_member(T set, const void *member);
extern void   Set_put   (T set, const void *member);
extern void  *Set_remove(T set, const void *member);
extern void   Set_map   (T set,
    void apply(const void *member, void *cl), void *cl);
extern void **Set_toArray(T set, void *end);
extern T      Set_union (T s, T t);
extern T      Set_inter (T s, T t);
extern T      Set_minus (T s, T t);
extern T      Set_diff  (T s, T t);

#undef
#endif

=============================set.c============================

#include <limits.h>
#include <stddef.h>
#include "mem.h"
#include "assert.h"
#include "arith.h"
#include "set.h"

#define T Set_T

//types
struct T{
    int length;
    unsigned timestamp;
    int (*cmp)(const void *x, const void *y);
    unsigned (*hash)(const void *x);
    int size;
    struct member{
        struct member *link;
        const void *member;
    } **buckets;
}

//static functions
static int cmpatom(const void *x, const void *y){
    return x != y;
}

static unsigned hashatom(const void *x){
    return (unsigned long)x>>2;
}

static T copy(T t, int hint){
    T set;

    assert(t);
    set = Set_new(hint, t->cmp, t->hash);
    {
        int i;
        struct member *q;
        for(i = 0; i < t->size; ++i){
            for(q = t->buckets[i]; q; q = q->link){
                struct member *p;
                const void *member = q->member;
                int i = (*set->hash)(member)%set->size;
                NEW(p);
                p->member = member;
                p->link = set->buckets[i];
                set->buckets[i] = p;
                set->length++;
            }
        }
    }

    return set;
}

//functions
T Set_new(int hint,
    int cmp(const void *x, const void *y),
    unsigned hash(const void *x)){
    T set;
    int i;
    static int primes[] = { 509, 509, 1021, 2053, 4093,
        8191, 16381, 32771, 65521, INT_MAX };
    
    assert(hint >= 0);
    for(i = 1; primes[i] < hint; ++i){
        ;
    set = ALLOC(sizeof(*set) +
        primes[i-1]*sizeof(set->buckets[0]));
    set->size = primes[i-1];
    set->cmp = cmp ? cmp : cmpatom;
    set->hash = hash ? hash : hashatom;
    set->buckets = (struct member **)(set + 1);
    for(i = 0; i < set->size; ++i){
        set->buckets[i] = NULL;
    }
    set->length = 0;
    set->timestamp = 0;
    
    return set;
}

int Set_member(T set, const void *member){
    int i;
    struct member *p;

    assert(set);
    assert(member);
    //search set for member
    i = (*set->hash)(member)%set->size;
    for(p = set->buckets[i]; p; p = p->link){
        if((*set->cmp)(member, p->member) == 0)
            break;
    }

    return p != NULL;
}

void Set_put(T set, const void *member){
    int i;
    struct member *p;

    assert(set);
    assert(member);
    //search set for member
    i = (*set->hash)(member)%set->size;
    for(p = set->buckets[i]; p; p = p->link){
        if((*set->cmp)(member, p->member) == 0)
            break;
    }
    if(p == NULL){
        //add member to set
        NEW(p);
        p->member = member;
        p->link = set->buckets[i];
        set->buckets[i] = p;
        set->length++;
    }else{
        p->member = member;
    }
    set->timestamp++;
}

void *Set_remove(T set, const void *member){
    int i;
    struct member **pp;

    assert(set);
    assert(member);
    set->timestamp++;
    i = (*set->hash)(member)%set->size;
    for(pp = &set->buckets[i]; *pp; pp = &(*pp)->link){
        if((*set->cmp)(member, (*pp)->member) == 0){
            struct member *p = *pp;
            *pp = p->link;
            member = p->member;
            FREE(p);
            set->length--;
            retunr (void *)member;
        }
    }

    return NULL;
}

int Set_length(T set){
    assert(set);
    return set->length;
}

void Set_free(T *set){
    assert(set && *set);
    if((*set)->length > 0){
        int i;
        struct member *p; *q;
        for(i = 0; i < (*set)->size; ++i){
            for(p = (*set)->buckets[i]; p; p = q){
                q = p->link;
                FREE(p);
            }
        }
    }

    FREE(*set);
}

void Set_map(T set,
    void apply(const void *member,  void *cl), void *cl){
    int i;
    unsigned stamp;
    struct member *p;

    assert(set);
    assert(apply);
    stamp = set->timestamp;
    for(i = 0; i < set->size; ++i){
        for(p = set->buckets[i]; p; p = p->link){
            apply(p->member, cl);
            assert(set->timestamp == stamp);
        }
    }
}

void **Set_toArray(T set, void *end){
    int i, j = 0;
    void **array;
    struct member *p;

    assert(set);
    array = ALLOC((set->length + 1)*sizeof(*array));
    for(i = 0; i < set->size; ++i){
        for(p = set->buckets[i]; p; p = p->link){
            array[j++] = (void *)p->member;
        }
    }
    array[j] = end;
    
    return array; 
}

T Set_union(T s, T t){
    if(s == NULL){
        assert(t);
        return copy(t, t->size);
    }else if( t == NULL){
        return copy(s, s->size);
    }else{
        T set = copy(s, Arith_max(s->size, t->size));
        assert(s->cmp == t->cmp && s->hash == t->hash);
        {
            //for each member q in t
            int i;
            struct member *q;
            for(i = 0; i < t->size; ++i){
                for(q = t->buckets[i]; q; q = q->link){
                    Set_put(set, q->member);
                }
            }
        }

        return set;
    }
}

T Set_inter(T s, T t){
    if(s == NULL){
        assert(t);
        return Set_new(t->size, t->cmp, t->hash);
    }else if( t == NULL){
        return Set_new(s->size, s->cmp, s->hash);
    }else if(s->length < t->length){
        return Set_inter(t, s);
    }else{
        T set = Set_new(Arith_min(s->size, t->size), 
            s->cmp, s->hash);
        assert(s->cmp == t->cmp && s->hash == t->hash);
        {
            int i;
            struct member *q;
            for(i = 0; i < t->size; ++i){
                for(q = t->buckets[i]; q; q = q->link){
                    if(Set_member(s, q->member)){
                        struct member *p
                        const void *member = q->member;
                        int i = (*set->hash)(member)%set->size;
                        NEW(p);
                        p->member = member;
                        p->link = set->buckets[i];
                        set->buckets[i] = p;
                        set->length++;
                    }
                }
            }
        }
        return set;
    }
}

T Set_minus(T t, T s){
    if(t == NULL){
        assert(s);
        return Set_new(s->size, s->cmp, s->hash);
    }else if(s == NULL){
        return copy(t, t->size);
    }else{
        T set = Set_new(Arith_min(s->size, t->size),
            s->cmp, s->hash);
        assert(s->cmp == t->cmp && s->hash == t->hash);
        {
            int i;
            struct member *q;
            for(i = 0; i < t->size; ++i){
                for(q = t->buckets[i]; q; q = q->link){
                    if(!Set_member(s, q->member)){
                        struct member *p;
                        const void *member = q->member;
                        int i = (*set->hash)(member)%set->size;
                        NEW(p);
                        p->member = member;
                        p->link = set->buckets[i];
                        set->buckets[i] = p;
                        set->length++;
                    }
                }
            }
        }

        return set;
    }
}

T Set_diff(T s, T t){
    if(s == NULL){
        assert(t);
        return copy(t, t->size);
    }else if(t == NULL){
        return copy(s, s->size);
    }else{
        T set = Set_new(Arith_min(s->size, t->size),
            s->cmp, s->hash);
        assert(s->cmp == t->cmp && s->hash == t->hash);
        {
            int i;
            struct member *q;
            for(i = 0; i < t->size; ++i){
                for(q = t->buckets[i]; q; q = q->link){
                    if(!Set_member(s, q->member)){
                        struct member *p;
                        const void *member = q->member;
                        int i = (*set->hash)(member)%set->size;
                        NEW(p);
                        p->member = member;
                        p->link = set->buckets[i];
                        set->buckets[i] = p;
                        set->length++;
                    }
                }
            }
        }
        {T u = t; t = s; s = u;}
        {
            int i;
            struct member *q;
            for(i = 0; i < t->size; ++i){
                for(q = t->buckets[i]; q; q = q->link){
                    if(!Set_member(s, q->member)){
                        struct member *p;
                        const void *member = q->member;
                        int i = (*set->hash)(member)%set->size;
                        NEW(p);
                        p->member = member;
                        p->link = set->buckets[i];
                        set->buckets[i] = p;
                        set->length++;
                    }
                }
            }
        }
        return set;
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章