编程珠玑 第十三章 搜索

从上一章的问题:生成[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

你可能感兴趣的:(编程珠玑)