从上一章的问题:生成[0, maxval]范围内m个随机整数的有序序列,不允许重复。实现伪代码:
initialize set S to empty size = 0 while size < m do t = bigrand() %d maxval if t is not in S insert t into S size ++ print the elements of S in sorted order
将生成的数据结构称为IntSet,指整数集合S。接口定义如下:
1 //Intset.h 接口定义头文件 2 typedef int bool; 3 #define true 0 4 #define false 1 5 void intset_init(int maxelements, int maxval); 6 void insert(int t); 7 bool isinset(int t); 8 int getsize(); 9 void report(int *v); 10 void destory_set();
int_set:初始化函数函数,参数 maxelements和maxval分别表示集合元素最大个数和集合中元素值的最大值,特定实现中可以忽略其中之一或两个都忽略;
insert:向集合中添加一个整数(前提需要先判断集合是否有已存在该值);
isinset:判断集合中是否存在元素t;
getsize:获得集合中元素数目;
report:把集合中的元素拷贝到v指向的内存区域;
destory_set: 销毁集合,释放集合所占用的空间;
2. 集合实现
以下是采用不同的数据结构实现的集合操作:
(1)使用整数数组实现集合。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <assert.h> 4 #include <malloc.h> 5 #include "Intset.h" 6 7 8 static int *set = NULL; 9 static int size; 10 //集合初始化, 11 //maxelements 为集合最大元素数目 12 //maxval为元素最大值 13 void intset_init(int maxelements, int maxval) 14 { 15 set = (int *)malloc((maxelements + 1)*sizeof(int)); 16 assert(set != NULL); 17 size = 0; 18 //哨兵元素,比元素最大值大1 19 set[0] = maxval + 1; 20 } 21 22 //二分查找,集合set已包含t,则返回位置;否则,返回-1; 23 int search(int t) 24 { 25 int l = 0, u = size - 1, p = -1, m; 26 m = (l + u) / 2; 27 //printf("l=%d, u=%d\n", l, u); 28 while(l < u) 29 { 30 //printf("l=%d, u=%d\n", l, u); 31 if( set[m] > t) 32 u = m - 1; 33 else if ( set[m] < t) 34 l = m + 1; 35 else 36 { 37 p = m; 38 break; 39 } 40 m = (l + u) / 2; 41 } 42 return p; 43 } 44 //判断元素t是否在集合t 45 bool isinset(int t) 46 { 47 if( search(t) == -1) 48 { 49 //printf("%d doesn't exist in set\n", t); 50 return false; 51 } 52 else 53 { 54 //printf("%d exist in set\n", t); 55 return true; 56 57 } 58 } 59 //把元素t插入到集合set中 60 void insert(int t) 61 { 62 assert(set != NULL); 63 int i, j; 64 for(i= 0; set[i] < t; i ++) 65 ; 66 if(set[i] == t) 67 return ; 68 for(j = size; j > i; j --) 69 set[j] = set[j - 1]; 70 set[i] = t; 71 size ++; 72 return ; 73 } 74 75 //获得集合set的大小 76 int getsize() 77 { 78 return size; 79 } 80 81 //集合set拷贝到数组v 82 void report(int *v) 83 { 84 int i; 85 for(i = 0; i < size; i ++) 86 { 87 v[i] = set[i]; 88 } 89 } 90 91 //删除集合set 92 void destory_set() 93 { 94 if(set != NULL) 95 { 96 free(set); 97 set = NULL; 98 } 99 }
(2)链表实现
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <assert.h> 4 #include <malloc.h> 5 #include "Intset.h" 6 7 8 static int *set = NULL; 9 static int size; 10 typedef struct node *pnode; 11 typedef struct node{ 12 int val; 13 pnode next; 14 15 }node; 16 17 static pnode head = NULL;//头部节点 18 static pnode sentinel = NULL;//哨兵节点 19 20 //集合初始化, 21 //maxelements 为集合最大元素数目 22 //maxval为元素最大值 23 void intset_init(int maxelements, int maxval) 24 { 25 26 if((head = sentinel = (pnode)malloc(sizeof(node))) != NULL) 27 { 28 sentinel->val = maxval; 29 sentinel->next = NULL; 30 size = 0; 31 } 32 else 33 { 34 printf("intset_init failed to malloc\n"); 35 exit(1); 36 } 37 } 38 39 //判断元素t是否在集合t 40 bool isinset(int t) 41 { 42 pnode p = head; 43 while(p != sentinel) 44 { 45 if(p->val == t) 46 return true; 47 else 48 p = p->next; 49 } 50 return false; 51 } 52 53 //递归插入元素t 54 pnode rinsert(pnode p, int t) 55 { 56 pnode pt; 57 if(p->val < t) 58 { 59 p->next = rinsert(p->next, t); 60 } 61 else 62 { 63 pt = (pnode)malloc(sizeof(node)); 64 pt->val = t; 65 pt->next = p; 66 size ++; 67 p = pt; 68 } 69 return p; 70 } 71 72 //把元素t插入到集合set中 73 void insert(int t) 74 { 75 head = rinsert(head, t); 76 return; 77 78 } 79 80 //非递归方法把元素t插入到集合set中 81 void insert_norec(int t) 82 { 83 pnode p = head, q = NULL, new; 84 85 while(p->val < t)//最后遇到大于t的元素或遇到哨兵节点 86 { 87 q = p; 88 p = q->next; 89 } 90 91 new = (pnode)malloc(sizeof(node)); 92 new->val = t; 93 new->next = p; 94 95 if(q == NULL)//插入到head头部节点 96 { 97 head = new; 98 } 99 else 100 { 101 q->next = new; 102 } 103 size ++; 104 return; 105 } 106 107 108 //获得集合set的大小 109 int getsize() 110 { 111 return size; 112 } 113 114 //集合set拷贝到数组v 115 void report(int *v) 116 { 117 int i=0; 118 pnode p = head; 119 while(p != sentinel) 120 { 121 v[i ++] = p->val; 122 p = p->next; 123 } 124 } 125 126 //删除集合set 127 void destory_set() 128 { 129 pnode p = head, q; 130 if(p != NULL) 131 { 132 q = p->next; 133 free(p); 134 p = q; 135 } 136 }
(4)二叉树实现
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <assert.h> 4 #include <malloc.h> 5 #include "Intset.h" 6 typedef struct node *pnode; 7 typedef struct node{ 8 int val; 9 pnode left;//左子树指针 10 pnode right;//右子树指针 11 }node; 12 //二叉树根节点 13 static pnode root; 14 static size; 15 16 17 //集合初始化, 18 //maxelements 为集合最大元素数目 19 //maxval为元素最大值 20 void intset_init(int maxelements, int maxval) 21 { 22 root = NULL; 23 size = 0; 24 } 25 //递归插入节点t 26 pnode rinsert(pnode p, int t) 27 { 28 if(p == NULL) 29 { 30 p = (pnode)malloc(sizeof(node)); 31 p->val = t; 32 p->left = p->right = NULL; 33 size ++; 34 } 35 else if( p->val > t) 36 { 37 p->left = rinsert(p->left, t); 38 } 39 else if(p->val < t) 40 { 41 p->right = rinsert(p->right, t); 42 } 43 return p; 44 } 45 //把元素t插入到集合set中 46 void insert(int t) 47 { 48 root = rinsert(root, t); 49 } 50 51 //判断元素t是否在集合t 52 bool isinset(int t) 53 { 54 pnode p = root; 55 while(p != NULL) 56 { 57 if(p->val > t) 58 p = p->left; 59 else if(p->val < t) 60 p = p->right; 61 else 62 return true; 63 } 64 return false; 65 } 66 int getsize() 67 { 68 return size; 69 } 70 //中序遍历二叉树 71 void mid_traverse(pnode p, int *v) 72 { 73 static int index = 0; 74 if(p == NULL) 75 return; 76 if(p == root) 77 index = 0; 78 mid_traverse(p->left, v); 79 v[index ++] = p->val; 80 mid_traverse(p->right, v); 81 82 } 83 84 //集合set拷贝到数组v 85 void report(int *v) 86 { 87 mid_traverse(root, v); 88 } 89 90 //递归删除节点 91 void destory_node(pnode p) 92 { 93 if(p == NULL) 94 return; 95 else if(p->left != NULL) 96 { 97 destory_node(p->left); 98 } 99 else if(p->right != NULL) 100 { 101 destory_node(p->right); 102 } 103 free(p); 104 } 105 106 //删除集合set 107 void destory_set() 108 { 109 destory_node(root); 110 root = NULL; 111 }
(4)位图实现(参考编程珠玑第1章)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <memory.h> 4 #include "Intset.h" 5 #define BITSPERWORD 32 6 #define SHIFT 5 7 #define MASK 0x1F 8 static unsigned int *bitmap;//位图指针 9 static unsigned int size = 0;//集合元素数目 10 static unsigned int max = 0;//集合中元素的最大值+1 11 // 数字k所对应位图的位置置为1 12 void set_bit(unsigned int k) 13 { 14 unsigned int byte_position; 15 unsigned short bit_position; 16 byte_position = k >> 5;//byte_position表示k在位图中的字节 17 bit_position = k & 0x1F;//bit_position表示k所在字节的位 18 /*printf("byte = %d bit = %d\n", byte_position, bit_position);*/ 19 bitmap[byte_position] = bitmap[byte_position] | (1 << bit_position); 20 } 21 22 //数字k所对应位图的位置清零 23 void clear_bit(unsigned int k) 24 { 25 unsigned int byte_position; 26 unsigned short bit_position; 27 byte_position = k >> 5; 28 bit_position = k & 0x1F; 29 /*printf("byte = %d bit = %d\n", byte_position, bit_position);*/ 30 bitmap[byte_position] = bitmap[byte_position] & ~(1 << bit_position); 31 } 32 33 //测试数字k所对应位图的位置为1或为0 34 bool test_bit(unsigned int k) 35 { 36 unsigned int byte_position; 37 unsigned short bit_position; 38 byte_position = k >> 5; 39 bit_position = k & 0x1F; 40 /*printf("byte = %d bit = %d\n", byte_position, bit_position);*/ 41 return bitmap[byte_position] & (1 << bit_position); 42 } 43 44 45 //初始化位图 46 void intset_init(int maxelements, int maxval) 47 { 48 unsigned int size = 1 + maxval/BITSPERWORD, i; 49 max = maxval; 50 printf("maxval = %u size = %u\n", maxval, size); 51 bitmap = (unsigned int *)malloc(size*sizeof(unsigned int)); 52 if(bitmap == NULL) 53 { 54 printf("Failed to malloc\n"); 55 return ; 56 } 57 memset(bitmap, 0, size*sizeof(unsigned int)); 58 size = 0; 59 return ; 60 } 61 62 void insert(int t) 63 { 64 set_bit(t); 65 size ++; 66 } 67 68 bool isinset(int t) 69 { 70 if( test_bit(t) == 0) 71 return false; 72 else 73 return true; 74 } 75 76 int getsize() 77 { 78 return size; 79 } 80 81 void report(int *v) 82 { 83 int i = 0, j = 0; 84 for(i = 0; i < max; i ++) 85 { 86 if(isinset(i) == true) 87 v[j ++] = i; 88 } 89 return; 90 } 91 92 void destory_set() 93 { 94 if(bitmap != NULL) 95 { 96 free(bitmap); 97 bitmap = NULL; 98 } 99 }
3.测试主函数实现
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <assert.h> 4 #include "Intset.h" 5 //产生区间[lower upper]内的随机数,参考编程珠玑第8章习题 6 int randInt(lower, upper) 7 { 8 assert( lower < upper); 9 return rand()%(upper - lower + 1) + lower; 10 } 11 //打印集合中的元素 12 void print(int arry[], int length) 13 { 14 int i; 15 printf("the set is \n"); 16 for(i = 0; i < length; i ++) 17 printf("%d\t", arry[i]); 18 printf("\n"); 19 } 20 //调用程序需要输入三个参数 count:集合数目 lower:集合下限 upper:集合上限 21 int main(int argc, char *argv[]) 22 { 23 24 int count = 0, i, lower, upper, *v; 25 if(argc != 4) 26 { 27 printf("USAGE:%s count lower upper \n", argv[0]); 28 return 1; 29 } 30 count = atoi(argv[1]); 31 lower = atoi(argv[2]); 32 upper = atoi(argv[3]); 33 printf("lower=%d upper=%d count=%d\n", lower, upper, count); 34 v = (int *)malloc(count * sizeof(int)); 35 intset_init(count , upper + 1); 36 i = count; 37 while(i > 0) 38 { 39 int t = randInt(lower, upper); 40 printf("rand=%d\n", t); 41 if( isinset(t) == false)//判断集合是否已存在该元素 42 { 43 insert(t); 44 i --; 45 } 46 47 } 48 report(v); 49 destory_set(); 50 print(v, count); 51 return 0; 52 }
4.以上各种数据结构实现集合操作的复杂度
集合表示 | O(每个操作的时间) 初始化 insert report |
总时间 空间 |
有序数组
有序链表
二叉树
箱
位向量 |
1 m m
1 m m
1 logm m
m 1 1
n 1 n
|
O(m^2) m
O(m^2) 2m
O(mlogm) 3m
O(m) 3m
O(n) n/b |