【问题标题】:Java recursive combine function to iterative equivalentJava递归组合函数到迭代等效
【发布时间】:2014-04-17 10:38:53
【问题描述】:

我有递归组合功能:

static void combinations2(String[] arr, int len, int startPosition, String[] result) {

    if (len == 0) {
        for (String n : result) {
            System.out.print(n + "  \n");

        }

        return;
    }

    for (int i = startPosition; i <= arr.length - len; i++) {
        result[result.length - len] = arr[i];
        combinations2(arr, len - 1, i + 1, result);
    }
}

输入:

 arr = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} - input array e.g.
 len = 3 - length of each combination
 startPosition = 0
 result - result of each combination

输出:

Item 1  
Item 2  
Item 3  

Item 1  
Item 2  
Item 4  

Item 1  
Item 2  
Item 5  

Item 1  
Item 3  
Item 4  

Item 1  
Item 3  
Item 5  

Item 1  
Item 4  
Item 5  

Item 2  
Item 3  
Item 4  

Item 2  
Item 3  
Item 5  

Item 2  
Item 4  
Item 5  

Item 3  
Item 4  
Item 5 

我应该怎么做才能将其更改为迭代替代?我阅读了有关堆栈的内容并写了几行..但是返回函数呢?怎么处理?

我做了这样的事情:

static void combinations2(String[] arr, int len, int startPosition, String[] result) {
        Stack<Integer> stos = new Stack<>();
        stos.push(startPosition);
        stos.push(len);

        int i = 0;
        while (!stos.isEmpty()) {
            len = stos.pop();
            startPosition = stos.pop();

            if (len == 0) {
                for (String n : result) {
                    System.out.print(n + "  \n");
                }            

                System.out.println("    ");
                stos.push(startPosition);
                stos.push(len+1);
            } else {

                for (i = startPosition; i <= arr.length - len; i++) {
                    result[result.length - len] = arr[i];

                    //combinations2(arr, len - 1, i + 1, result);
                    stos.push(i + 1);
                    stos.push(len - 1);
                    break;

                }
            }  
        }
    }

我得到了输出:

Item 1  
Item 2  
Item 3  

Item 1  
Item 2  
Item 4  

Item 1  
Item 2  
Item 5 

有人可以告诉我如何生成后续步骤吗?

【问题讨论】:

  • 第一个输出不是你想要的输出吗?您想通过第二个程序实现什么类型的输出?
  • 一模一样,只是使用了迭代的方法……

标签: java recursion iteration


【解决方案1】:

下面的类是一个返回组合的 Iterable。使用方法见main。运行 main 方法进行测试。

组合是惰性创建的,因此从 10000000 池中读取 10 个元素的前 100 个组合不会很慢。

这个类还缩短了对不可能场景的任何探索,即对于 5 个元素中的 3 个的组合,将第 4 个元素放在第一个位置是没有意义的,因为这将导致第 5 个元素在第二个位置,并且没有元素留给最后一个位置。

递归算法的一般迭代版本使用堆栈来模拟传递给同一函数的变量。

public class Combinations<T> implements Iterable<List<T>> {

    private final List<T> items;
    private final int size;

    public static <T> Combinations<T> of(List<T> items, int size) {
        return new Combinations<T>(items, size);
    }

    private Combinations(List<T> items, int size) {
        if (items.size() < size) throw new IllegalArgumentException();
        this.items =  items;
        this.size = size;
    }

    public Iterator<List<T>> iterator() {
        return new Iterator<List<T>>() {        
            private final int[] positions = new int[size];              
            private boolean more = true;
            {
                for(int i = 0;i < positions.length;i++) {
                    positions[i] = i;
                }
            }

            public boolean hasNext() {
                return more;
            }

            public List<T> next() {
                if (!more) throw new NoSuchElementException();
                List<T> ret = new ArrayList<T>();
                for (int i = 0;i < positions.length;i++) {
                    ret.add(items.get(positions[i]));
                }
                int advanceIdx = positions.length - 1;
                while(advanceIdx > -1) {
                    if (positions[advanceIdx] == items.size() - size + advanceIdx) {
                        advanceIdx--;
                    } else {
                        positions[advanceIdx]++;
                        for (int i = 1;i + advanceIdx < positions.length;i++) {
                            positions[advanceIdx+i] = positions[advanceIdx] + i; 
                        }
                        return ret;
                    }
                }
                more = false;
                return ret;
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

        };
    }

    public static void main(String[] args) {
        for(List<String> s : Combinations.of(Arrays.asList("A", "B", "C", "D", "E"), 3)) {
            System.out.println(s);
        }
    }
}

【讨论】:

  • 感谢您的解决方案。 “递归算法的一般迭代版本使用堆栈来模拟传递给同一函数的变量”。我通常会尝试做什么。
  • @cichacz 你的问题是你没有回溯堆栈,这就是为什么你的解决方案只返回最后一个元素更改的解决方案。
  • 这是堆栈的一般原则:您将路径部分添加到堆栈中,因为您将在递归中更深入,并在您回溯时弹出堆栈。您还可以在堆栈中存储 2 个变量:startPosition 和 length,但由于可以使用 startPosition 表示长度,因此您只需要 1 个变量。
猜你喜欢
  • 2016-03-01
  • 2021-12-31
  • 1970-01-01
  • 2019-06-20
  • 2021-03-17
  • 2019-04-03
  • 2012-08-29
  • 2011-05-05
  • 2012-10-17
相关资源
最近更新 更多