zoukankan      html  css  js  c++  java
  • 编程珠玑 第十三章 搜索

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

  • 相关阅读:
    Asp.net分页控件AspNetPager的使用(DataList和Reapter结合Linq的编辑与删除)
    Zend Framework使用Extjs进行数据库交互和分页
    课程设计之(struts2+Hibernate)航空订票系统
    课程设计之(ZendFrameWrok)构建的航空订票系统网站
    Ubuntu10.10 Zend FrameWork配置及helloworld显示
    ExtJs、Struts2、Hibernate3.2登录页面的简单实现
    Asp.net的FileUpload控件的文件上传与Extjs文件上传的简单Demo
    学习linux的一些网络资源
    100条超搞笑的“雷人”QQ/MSN 签名
    超难的75道逻辑思维题
  • 原文地址:https://www.cnblogs.com/bigrabbit/p/2671125.html
Copyright © 2011-2022 走看看