Chinaunix首页 | 论坛 | 博客
  • 博客访问: 219695
  • 博文数量: 42
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 420
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-09 10:55
个人简介

每天改变一点点,生活充满了惊喜。

文章分类

全部博文(42)

文章存档

2016年(8)

2015年(29)

2014年(5)

我的朋友

分类: C/C++

2015-04-20 21:53:18

利用动态规划的思想,也可以解决求子集的问题。
例如 要求{1,2,3} 的子集,可以转化为求{2,3}的子集,再把元素1 加入到{2,3}的所有子集中,形成{1,2,3}的所有子集。
以此类推,求{2,3}的子集可以转化为求{3}的子集,最终转化为求{}的子集,这是一个已知问题,空集的子集就是空集。

注意,这个方法因为要保存子集的状态,所以花费的内存会较多。

  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. int get_sub_set(char * set, char ** set_list, int n);

  4. /* Usage:获取所有子集
  5.  * @PARAM : set 在源集合中,求子集的开始位置,
  6.  * 每次递归相当对 set 指针指向的字符至结束字符求子集
  7.  * @PARAM : set_list 字符数组,每个数组元素为一个子集字符串
  8.  * @PARAM : n 集合元素个数
  9.  * @RETUEN : 子集的个数
  10.  * */
  11. int get_sub_set(char * set, char ** set_list, int n)
  12. {
  13.     int count = 1;
  14.     if ( set[0] != '\0'){
  15.         /* 递归直到源集合中最后一个元素 */
  16.         count = get_sub_set( set + 1 , set_list, n);

  17.         int curr = count; /*递归返回时子集个数,即 set[0] 后面左右字符的子集个数*/
  18.         count = count * 2; /* 加入set[0] 字符,形成包含 set[0]字符的子集个数 */
  19.     
  20.         int i = curr ; /* 为新产生的子集分配内存 */
  21.         for (; i < count; i ++){
  22.             set_list[i] = (char *) malloc( (n + 1) * sizeof(char) );
  23.         }

  24.         i = curr ; /* 加入当前字符,形成新的子集 */
  25.         int j = 0;
  26.         int k = 0;
  27.         for (; j < curr; j ++){
  28.             k = 0;
  29.             /* 逐个拷贝前面产生的子集,然后加入当前字符 */
  30.             while (set_list[j][k] != '\0'){
  31.                  set_list[i][k] = set_list[j][k];
  32.                  k ++;
  33.             }
  34.              set_list[i][k] = set[0];
  35.             set_list[i][k + 1] = '\0';
  36.             i ++;
  37.         }
  38.     }

  39.     /* 返回已经产生的子集个数 */
  40.     return count;
  41. }

  42. int main()
  43. {
  44.     //char set[] = "0123456789abcdefghij";
  45.     char set[] = "012";
  46.     int set_count = strlen(set);
  47.     int sub_set_count = 1 << set_count; /*所有子集的数目*/

  48.     char **set_list; /* 字符串数组,保存所有的子集 */
  49.     set_list = (char **) malloc( sub_set_count * sizeof(char *));
  50.     /* 初始为空集 */
  51.     set_list[0] = (char *) malloc( (set_count + 1 ) * sizeof(char) );
  52.     set_list[0][0] = '\0';

  53.     sub_set_count = get_sub_set(set, set_list, set_count);

  54.     /* 打印所有子集,并释放堆内存 */
  55.     int i = 0;
  56.     for (; i < sub_set_count; i++){
  57.         printf("%s \n",set_list[i]);
  58.         free(set_list[i]);
  59.     }

  60.     free(set_list);
  61.     return 0;
  62. }

程序的输出为:




如果集合字符串为"0123456789abcdefghij" ,20个字符,算法的执行时间为15s左右
求集合子集的几种方法,我都是在同一台服务器上执行的,性能的对比可以做一个简单的参考。


BTW,总结的有些匆忙,如有误之处,希望不吝指教。


阅读(3802) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~