递归实现集合求解

数据库环境:SQL SERVER 2005

  在群里看到一道题,截图如下:

  可能有些朋友还看不懂题目的意思,我们现在就来分析一下。假设有3种产品A、产品B、产品C,产品A和产品B存在替换关系

如果产品A和产品B中任何一种产品和产品C存在替换关系,则它们就是一组。

  实现思路:把存在替换关系的任意2种产品放到集合1中,然后遍历后续产品,如果满足关系的则加入集合1,否则,新建集合2,

遍历符合集合2的产品并加入。

/*测试数据*/
WITH    tab
          AS ( SELECT   1 id ,
                        ‘121500125‘ fru ,
                        ‘121500132‘ sub_fru
               UNION ALL
               SELECT   2 id ,
                        ‘121500125‘ fru ,
                        ‘5B19A4567R‘ sub_fru
               UNION ALL
               SELECT   3 id ,
                        ‘121500132‘ fru ,
                        ‘121500125‘ sub_fru
               UNION ALL
               SELECT   4 id ,
                        ‘121500132‘ fru ,
                        ‘5B19A4567R‘ sub_fru
               UNION ALL
               SELECT   5 id ,
                        ‘121500178‘ fru ,
                        ‘121500180‘ sub_fru
               UNION ALL
               SELECT   6 id ,
                        ‘121500180‘ fru ,
                        ‘121500178‘ sub_fru
               UNION ALL
               SELECT   7 id ,
                        ‘121500180‘ fru ,
                        ‘SB19A46291‘ sub_fru
             ),/*递归,遍历数据加入关系集合*/
        t ( id, fru, sub_fru, fru_r, gp )
          AS ( SELECT   id ,
                        fru ,
                        sub_fru ,
                        CONVERT(VARCHAR(100), fru + ‘,‘ + sub_fru) AS fru_r ,--关系集合
                        1 AS gp--组号
               FROM     tab
               WHERE    id = 1
               UNION ALL
               SELECT   t1.id ,
                        t1.fru ,
                        t1.sub_fru ,
                        CONVERT(VARCHAR(100), CASE WHEN ( CHARINDEX(t1.fru,
                                                              t2.fru_r) > 0
                                                          OR CHARINDEX(t1.sub_fru,
                                                              t2.fru_r) > 0
                                                        )--如果新产品和关系中的产品有关系,则加入
                                                   THEN CASE WHEN CHARINDEX(t1.fru,
                                                              t2.fru_r) = 0
                                                             THEN t2.fru_r
                                                              + ‘,‘ + t1.fru
                                                             WHEN CHARINDEX(t1.sub_fru,
                                                              t2.fru_r) = 0
                                                             THEN t2.fru_r
                                                              + ‘,‘
                                                              + t1.sub_fru
                                                             ELSE t2.fru_r
                                                        END
                                                   ELSE t1.fru + ‘,‘
                                                        + t1.sub_fru--新建另一组的关系集合
                                              END) AS fru_r ,
                        CASE WHEN ( CHARINDEX(t1.fru, t2.fru_r) > 0
                                    OR CHARINDEX(t1.sub_fru, t2.fru_r) > 0
                                  ) THEN t2.gp
                             ELSE t2.gp + 1
                        END AS gp
               FROM     tab t1 ,
                        t t2
               WHERE    t1.id = t2.id + 1
             ),/*取出每组集合中的最大子集*/
        t1
          AS ( SELECT   gp AS id ,
                        MAX(fru_r) AS fru
               FROM     t
               GROUP BY gp
             )/*按逗号分割关系产品*/
    SELECT  t1.id ,
            col = CAST(SUBSTRING(fru, number,
                                 CHARINDEX(‘,‘, fru + ‘,‘, number) - number) AS VARCHAR(100))
    FROM    t1
            CROSS APPLY master..spt_values
    WHERE   type = ‘P‘
            AND number >= 1
            AND number <= LEN(fru + ‘a‘)
            AND CHARINDEX(‘,‘, ‘,‘ + fru, number) = number

  当然,也可以在递归的时候就把每组的产品都罗列出来,就省去后面拆分字符串的步骤。不过,这样实现也比较麻烦。

  结果如下图:

时间: 2024-10-11 21:30:05

递归实现集合求解的相关文章

递归下降来求解中缀或者后缀或者前缀表达式

  学习数据结构的时候学到栈的时候都会学习使用栈来实现求解中缀表达式,思路就是扫描一遍,数字输出,符号根据优先级决定入栈和出栈的时间,然后生成后缀表达式,对后缀表达式的求解是容易的,直接扫描一遍,遇到数字入栈,遇到操作符就直接取栈顶的两个元素做运算. 好久之前实现上面所说的程序是第一个感受"编译"的感觉,感觉很爽,因此一直想学一下真正的编译原理,龙书比较深奥,一直未得其奥义.这两天阅读了vczh大大的系列文章 <手写语法分析器>.<正则表达式引擎>等文章,颇有感

用递归和非递归的方法求解n的k次方

递归的方法 #include<stdio.h> int my_power(int n,int k) { if (k-- > 1) n*=my_power(n, k); return n; } int main() { int n = 0, k = 0, ret = 0; scanf("%d%d", &n, &k); ret = my_power(n, k); printf("%d^%d=%d\n", n, k, ret); syst

递归O(NlgN)求解逆序数

导言 第一次了解到逆序数是在高等代数课程上.当时想计算一个数列的逆序数直觉就是用两重循环O(n^2)暴力求解.现在渐渐对归并算法有了一定的认识,因此决定自己用C++代码小试牛刀. 逆序数简介 由自然数1,2…,n组成的不重复的每一种有确定次序的排列,称为一个n级排列(简称为排列):或者一般的,n个互不同元素排成一列称为“一个n级排列”.例如,1234和4312都是4级排列,而24315是一个5级排列. 在一个n级排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一

sicily 1156 二叉树的遍历 前序遍历,递归,集合操作

1156. Binary tree Constraints Time Limit: 1 secs, Memory Limit: 32 MB Description Your task is very simple: Given a binary tree, every node of which contains one upper case character (‘A’ to ‘Z’); you just need to print all characters of this tree in

分治策略(求解递归式的方法)

分解:将原问题划分成形式相同的子问题,规模可以不等,对半或2/3对1/3的划分. 解决:对于子问题的解决,很明显,采用的是递归求解的方式,如果子问题足够小了,就停止递归,直接求解. 合并:将子问题的解合并成原问题的解. 这里引出了一个如何求解子问题的问题,显然是采用递归调用栈的方式.因此,递归式与分治法是紧密相连的,使用递归式可以很自然地刻画分治法的运行时间.所以,如果你要问我分治与递归的关系,我会这样回答:分治依托于递归,分治是一种思想,而递归是一种手段,递归式可以刻画分治算法的时间复杂度.

【万字总结】探讨递归与迭代的区别与联系及如何求解10000的阶层

递归和迭代 这两个概念也许很多童鞋依旧分不清楚,下面通过求解斐波那契数来看看它们俩的关系吧. 斐波那契数的定义: f0=0 f1=1 fi=fi?1+fi?2(i>1) 递归: (factorial 6) (* 6 (factorial 5)) (* 6 (* 5 (factorial 4))) (* 6 (* 5 (* 4 (factorial 3)))) (* 6 (* 5 (* 4 (* 3 (factorial 2))))) (* 6 (* 5 (* 4 (* 3 (2 (factori

递归式的三种求解方式

求解递归式对于分冶算法的重要性不言而喻 以下介绍了三种求解递归式的方法 1,代换法: 缺点:代换法主要的缺点在于,对于任何递归式,我们先得去猜其解,对于猜错了同学,如果不幸猜出的结果和正确结果相差太大,虽然可以推导,但是意义不大: 优点:代换法相较于递归树法更为严谨,相较于主定理应用范围更广,主定理只能求解类似于T(n) = aT(n/b)+n/c这种形式的递归式: 下面给出一个递归表达式T(n) = 2T(n/2)+n,求其解: 首先猜一下其解为O(nlgn);那么我们只需要证明T(n)<cn

JAVA求解全排列

一,问题描述 给定一个字符串,求出该字符串的全排列. 比如:"abc"的全排列是:abc.acb.bac.bca.cab.cba 二,实现思路 采用递归的方式求解.每次先选定一个字符,然后进行“若干次”交换,求出在选定这个字符的条件下,所有的全排列,并把字符“复位”再交换回来.至此,一趟全排列完成.第二趟,选定下一个字符,然后进行“若干次”交换,求出在选定这个字符的条件下,所有的全排列,并把字符“复位”再交换回来...... 就类似于:(参考网上的解释如下:) 设R={r1,r2,..

分治法与递归编程步骤

分治法是一种很强大的算法设计方法.基本思想是:将原问题分解为几个规模小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 在分治策略中,递归地求解一个问题,在每层递归中应用如下三个步骤: (1)分解(Divide):将原问题分解为一些子问题,子问题的形式与原问题一样,只是规模更小. (2)解决(Conquer):递归地解出子问题.如果子问题规模足够小,则停止递归,直接求解. (3)合并(Combine):将子问题的解组合成原问题的解. 分治思想体现在编码上,