C算法精解 ->集合->实现和分析

 前面已经介绍了链表、栈和队列的实现,也了解到在栈和队列的实现过程中,都用到的单链表的函数接口。下面介绍新的:集合。

 集合是不同对象的无序的聚集,集合的2个重要特点就是无序、和无重复性。在高中已经了解集合的很多知识,下面来回忆下,集合的特性。


C算法精解 ->集合->实现和分析_第1张图片

 集合的定义和实现,同样也是用了单链表的函数接口,只要认真阅读,肯定能理解



//
//  Set.h
//  Algorithms&Data_structures
//
//  Created by TTc on 15-2-2.
//  Copyright (c) 2015年 TTc. All rights reserved.
//

#ifndef __Algorithms_Data_structures__Set__
#define __Algorithms_Data_structures__Set__

#include <stdlib.h>
#include "List.h"

/* implement sets as linked list */

typedef List Set;

/* public interface */

void set_init(Set *set,int (*match)(const void *key1,const void * key2),
              void  (*destroy)(void *data));


int set_insert(Set *set, const void * data);

int set_remove(Set *set, void ** data);

int set_union(Set *setu,const Set *set1,const Set *set2);

int set_intersection(Set *seti,const Set *set1,const Set *set2);

int set_difference(Set *setd,const Set *set1,const Set *set2);

int set_is_number(const Set *set,const void *data);

int set_is_subset(const Set *set1,const Set *set2);

int set_is_equal(const Set *set1,const Set *set2);

#define set_destroy list_destroy

#define set_size(set)  ((set)->size)

#endif /* defined(__Algorithms_Data_structures__Set__) */

//
//  Set.c
//  Algorithms&Data_structures
//
//  Created by TTc on 15-2-2.
//  Copyright (c) 2015年 TTc. All rights reserved.
//

#include "Set.h"

#include <stdlib.h>

void
set_init(Set *set,int (*match)(const void *key1,const void * key2),
         void  (*destroy)(void *data)){
    list_init(set, destroy);
    set->match = match;
}

/*
   将一个成员插入到集合中,由于集合中的成员只能出现一次,因此将首先调用set_is_member以确保集合中不会已经包含了待插入的成员;若集合中不存在待插入的成员,就调用list_ins_next将待插入的成员插入到集合中
 */

/* set_inert的复杂度为O(n)级,因为set_is_member需要遍历整个集合,需要O(n) ;而list_ins_next则以O(1)插入*/
int
set_insert(Set *set, const void * data){
    if(set_is_number(set, data)){
        return 1;
    }
    return list_ins_next(set, list_tail(set), data);
}

/*
 set_remove 复杂度为O(n) ,n为集合的成员size
 */
int
set_remove(Set *set, void ** data){
    ListElmt *member,*prev;
    prev = NULL;
    //遍历一次 单链表
    for(member = list_head(set);member != NULL;member = list_next(member)){
        if(set->match(*data,list_data(member)))
            break;
        prev = member;
    }
    if(member == NULL)
        return -1;
        return list_rem_next(set, prev, data);
}

/*
    set_union
 1:操作将建立一个集合,记做setu,由参数set1与set2所指定的集合的并集结果;      
 2:复杂度为O(mn) ,m,n分别为集合set1与set2的成员个数
 3:在第一个循环中,遍历了set1中的每个成员并且把他们插入setu中,这个过程的时间复杂度O(m)
 5:在第二个循环中,遍历了set2中的每个成员并且把他们插入setu中,这个过程的时间复杂度O(n)
   而这个循环需要包含时间复杂度为O(n)的set_is_member,因此第二次循环的总体复杂度为O(mn)
 6:由于这两个循环是顺序执行的,因此set_union的运行时复杂度比单独执行这两次循环还要大,
    记为O(mn)
 */
int
set_union(Set *setu,const Set *set1,const Set *set2){
    ListElmt *member;
    void *data;
    
    set_init(setu, set1->match, NULL);
    // insert the members  of the first set
    for (member = list_head(set1); member != NULL; member = list_next(member)) {
        data =  list_data(member);
        if(list_ins_next(setu, list_tail(setu), data) != 0 ){
            set_destroy(setu);
            return -1;
        }
    }
    // insert the members  of the second set
    for (member = list_head(set2); member != NULL; member = list_next(member)) {
        if(set_is_number(set1, list_data(member))){
            continue;
        } else{
            data = list_data(member);
            if(list_ins_next(setu, list_tail(setu), data)){
                set_destroy(setu);
                return -1;
            }
        }
    }
    return 0;
}
/*
 set_intersection
 1:操作将建立一个集合,记做seti,由参数set1与set2所指定的集合的交集结果;
 2:复杂度为O(mn) ,m,n分别为集合set1与set2的成员个数
 */
int
set_intersection(Set *seti,const Set *set1,const Set *set2){
    ListElmt* member;
    void *data;
    set_init(seti, set1->match, NULL);
    for (member = list_head(set1); member != NULL; member = list_next(member)) {
        if(set_is_number(set2,list_data(member))){
            data = list_data(member);
            if(list_ins_next(seti, list_tail(seti), data) != 0){
                set_destroy(seti);
                return -1;
            }
        }
    }

    return 0;
}

/*
 set_difference
 1:操作将建立一个集合,记做setd,由参数set1与set2所指定的集合的差集结果;
 2:复杂度为O(mn) ,m,n分别为集合set1与set2的成员个数
 */
int
set_difference(Set *setd,const Set *set1,const Set *set2){
    ListElmt* member;
    void *data;
    set_init(setd, set1->match, NULL);
    for (member = list_head(set1); member != NULL; member = list_next(member)) {
        if(!set_is_number(set2,list_data(member))){
            data = list_data(member);
            if(list_ins_next(setd, list_tail(setd), data) != 0){
                set_destroy(setd);
                return -1;
            }
        }
    }
     return 0;
}

/*
   set_is_member用来判断某个成员是否再集合中出现过     复杂度为O(n) ,n为集合的成员size
 */
int
set_is_number(const Set *set,const void *data){
    ListElmt *member ;
    //O(n)
    for (member = list_head(set); member != NULL; member = list_next(member)) {
        if(set->match(data,list_data(member))){
            return 1;
        }
    }
    return 0;
}
/*
 set_is_subset 操作用来判断集合set1是否为集合set2的子集合

 1:由于一个集合是另外一个集合的子集,则set1所包含的成员个数必须要小于等于set2所包含的
   成员个数,因此首先比较它们的成员个数
 
 复杂度为O(mn),m,n分别为set1与set2的成员个数size
 */
int
set_is_subset(const Set *set1,const Set *set2){
    ListElmt *member;
    if(set_size(set1) > set_size(set2)){
        return 0;
    }
    for (member = list_head(set1); member != NULL; member = list_next(member)) {
        if(!set_is_number(set2,list_data(member)))
            return 0;
    }
     return 1;
}
/*
 set_is_equal用来判断set1与set2是否相等
 1:因为两个相等的集合必然有相同的成员个数size,所以就从比较它们的成员个数size开始
 2:若两个集合的成员个数不等,则两个集合必然不想等
 3:如果两个集合的成员个数相同,只需要确定set1是否为set2的子集就可以返回结果了,
 可以通过调用set_is_subset来实现
 4:set_is_subset 运行时 复杂度为O(mn),m,n分别为set1与set2的成员个数size
 */
int
set_is_equal(const Set *set1,const Set *set2){
    if(set_size(set1) != set_size(set2)){
        return 0;
    }
    return set_is_subset(set1, set2);
}









你可能感兴趣的:(C算法精解 ->集合->实现和分析)