【问题标题】:Permutation Iterator in javajava中的置换迭代器
【发布时间】:2018-03-25 16:41:08
【问题描述】:

我想要一个类,它接受一个正整数并生成一个迭代器,让我遍历正整数下正数列表的所有可能排列。
例如。 permulator p = paermulator(3)
p.next() -> [0,1,2]
p.next() -> [0,2,1]
p.next() -> [1,0,2]
p.next() -> [1,2,0]
...
在这种情况下,这是 6 种可能的排列。 我设计了一个类,但速度非常慢,我想让迭代更快。 这是我的设计:
(我这样做是为了这似乎是可能的。)

    package Mathematica.complexity;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.NoSuchElementException;

/**
 * Tthis will be a class that demonstrate what we call: 
 * a factorial complexity algorithm 
 * it's going to print all the possible permutations of some sort of collection 
 * in java. 
 * <br>
 * A recursive data structure that resembles the process of permutating. 
 * @author dashie
 *
 */
public class FactorialComplexity implements Iterator<List<Integer>>
{

 private List<Integer> G_Data; 


    // sub recursive structure of the class. 
    private FactorialComplexity G_next = null; 

    private int G_ChoosenIndex = 0; 

    private boolean G_canProduceNextElement= true;

    public static void main(String[] args) 
    {


    }

    public FactorialComplexity(int NumbersofElements)
    {
        if(NumbersofElements <0)throw new AssertionError();
        this.G_Data = new LinkedList<>();

        for(int i =0; i< NumbersofElements;i++)this.G_Data.add(i);

        this.prepareSubStructure();

    }

    protected FactorialComplexity(List<Integer> argIn)
    {

        this.G_Data = argIn;
        this.prepareSubStructure();

    }


    /**
     * Using the internal index to return the current element it is 
     * pointing at. 
     * <br></b>I doesn't increment the internal pointer. </b>
     * @return
     */
    public Integer getChoosenElement()
    {
        //if(this.G_Data.size() == 0)return null;
        return this.G_Data.get(this.G_ChoosenIndex);
    }

    /**
     * This function serves for the iterator. 
     * @return
     */
    public List<Integer> getPermutation()
    {
        // two of the base case. 
        if(this.G_Data.size()==0)
        {
            return new LinkedList<>();
        }
        if(this.G_Data.size()==1)
        {
            List<Integer> temp = new LinkedList<>();
            temp.add(this.G_Data.get(0));
            return temp;
        }

        return this.getPermutation_part1(new LinkedList<Integer>());
    }

    private List<Integer> getPermutation_part1(List<Integer> argIn)
    {
        argIn.add(getChoosenElement());
        argIn.addAll(this.G_next.getPermutation());
        return argIn;
    }


    /**
     * <ol>
     * <li>If the sub-structure has next element, increment the sub structure.
     * <li>If not, increment the index in this instance and recreate sub structure. 
     * <li>be careful about the base case please. 
     * </ol>
     * 
     * @return 
     * if this, including sub structure should be incremented. 
     * 
     */
    protected boolean increment()
    {

        if(this.G_next!= null)
        {
            boolean temp = this.G_next.increment();
            int pointer = this.G_ChoosenIndex;
            if(this.G_ChoosenIndex+1<this.G_Data.size())
            {
                if(temp)
                {
                    this.G_ChoosenIndex++;
                    this.prepareSubStructure();
                }
                return false;
            }
            else
            {
                return (this.G_ChoosenIndex+1 == this.G_Data.size())&&temp;
            }
        }
        else
        {
            //empty means not choice can make. 
            return true;
        }
    }




    @Override
    /**
     * All the nodes are at its last index. 
     */
    public boolean hasNext()
    {
        if(!this.G_canProduceNextElement)return false;
        if(this.isAllPointingAtLastIndex())this.G_canProduceNextElement=false;
        return true;
    }


    /**
     * This index in this class instance and 
     * all its sub structure are pointing at the last index? 
     * @return
     */
    boolean isAllPointingAtLastIndex()
    {
        if(this.G_Data.size()<=1)
        {
            return true;
        }
        return this.G_ChoosenIndex+1
                ==
               this.G_Data.size()&&this.G_next.isAllPointingAtLastIndex();
    }



    @Override
    public List<Integer> next() 
    {

        List<Integer> result = this.getPermutation();
        this.increment();
        return result;
    }

    public String toString()
    {
        String s = new String();
        s+= this.G_Data+":"+this.G_ChoosenIndex+"->";
        if(this.G_next!= null)s+= this.G_next.toString();
        return s;
    }



    /**
     * <ol>
     * <li>Base case: the list in this instant is empty. 
     * <li>Make a copy of the local collection, excluding the 
     * element the pointer is pointing to
     * <li>Make connect the this object to its sub structure and recurse. 
     * </ol>
     */
    protected void prepareSubStructure()
    {
        if(this.G_Data.size() == 0)return;
        List<Integer> temp = new LinkedList<>();
        temp.addAll(this.G_Data);
        temp.remove(this.G_ChoosenIndex);
        this.G_next = new FactorialComplexity(temp);
        this.G_next.prepareSubStructure();
    }


    public static int factorial(int n)
    {
        if(n<0)return 0;
        if(n<=1)return 1;
        return n*factorial(n-1);
    }

}

总结一下: 该类像链表一样是递归的,每个节点都包含一个指示它指向的元素的索引以及从前一个节点传递的所有元素的列表。

这种方法有多幼稚?我怎样才能让它更快?

【问题讨论】:

  • 请阅读 java 命名约定。令人惊讶的是,您以某种方式违反了其中的大多数。字段名称小写。方法或参数名称相同。并且没有 _ 除非是常量。
  • 是的教授,我交作业的时候会改的,请放心。????????????????
  • 我在这里写并解释了一个迭代器stackoverflow.com/a/10117424/312172 - 也许你有兴趣看看。
  • 我想我理解这个想法,它看起来很聪明,但它仍然在某种程度上使用递归。我喜欢这个解决方案!
  • 您希望我们花费我们的时间来帮助您解决问题。你不觉得给 us 代码来阅读对我们更有效的代码是合理的吗?你就像“是的,我知道这是错的,但是当我向你们展示这些东西时我为什么要担心”

标签: java time-complexity permutation


【解决方案1】:

这是一个更好的解决方案,灵感来自https://stackoverflow.com/a/10117424/312172

为了实现这一目标,我们不是得到一个杂乱无章的元素列表,而是关注我们在从列表中扣除元素时所做的选择。 给函数一个大小,以及一个小于阶乘(大小)的数字;它将返回我们需要做出的一系列选择以获得排列。

例如:
getTheIndexOfSelection(100,5)-> 对于 5 个元素的列表,我们想要第 100 个排列。

它应该输出: [4, 0, 2, 0, 0]

这意味着,删除索引 4 处的元素,对于被删除的列表,删除 0 处的元素......

如果列表是[1,2,3,4,5];这将是procujure:
[1,2,3,4,5] 删除索引 4 -> 5
[1,2,3,4] 删除索引 0 -> 1
[2,3,4] 删除索引 2 -> 4
[2,3] rovmove 索引 0 -> 2
[3] 删除索引 0 -> 3
我们顺序删除的所有元素都是排列。

/**
     * Feed this function a number, it gives you a sequence of choices 
     * to make a permutation. 
     * <br>
     * if this return [0,0,0,0]
     * it means remove element at 0, and then remove again... until 
     * reaches the end. 
     * @return
     * 
     * @param
     * len: the length of the list
     * n: the number that got match to a certain permutation. 
     */
    public static int[] getTheIndexOfSelection(int n, int size)
    {
        int[] lst = new int[size];
        return getTheIndexOfSelection( n,  size,  0, lst);

    }




 private static int[] getTheIndexOfSelection(int n, int size, int index, int[] lst)
    {
        if(size==1)
        {
            int[] result = {0}; // a list of one element, you can only choose the one that is in it
            // which is at index 0; 
            return result;
        }

        if(n >= factorial(size))return null; // This is not possible to do. 

        size-=1;
        int   firstchoice = n/factorial(size);

        lst[index]        = firstchoice;

        n = n-firstchoice*factorial(size);

        if(size>1)return getTheIndexOfSelection(n ,size, index+1, lst);
        return lst;
    }

这是一个更好的解决方案,因为:

  1. 速度实际上取决于阶乘函数,假设阶乘非常快,这将是 o(n)。
  2. 它将数字与排列相匹配,从而可以扩展地图和迭代器等内容。
  3. 这不是完整的解决方案,现在剩下要解决的部分几乎是微不足道的。

【讨论】:

    【解决方案2】:

    使用堆算法的实现。它即时计算下一个排列。并且只有一个数组复制

    
    
    import java.util.Arrays;
    import java.util.Iterator;
    
    class Permutator<E> implements  Iterator<E[]>{
    
        E[] arr1 = null;
        E[] arr2 = null;
        int size;
        int[] stack = null;
    
        int index = 0;
        public Permutator( E[] arr ){
    
            if( arr.length > 0 ){
                arr1 = arr;
    
                size = arr1.length;
                arr2 = Arrays.copyOf(arr1, size);
    
                stack = new int[size];
                Arrays.fill(stack, 0);
            }
        }
    
        @Override
        public boolean hasNext() {
            return (null != arr1 && arr1.length > 0);
        }
    
        @Override
        public E[] next() {
    
            // start computing.
            // We will return original array as value of last permutation.
            // This is to make "hasNext() " implementation easy.
            updateValue();
            return arr2;
        }
    
        protected void updateValue(){
    
            boolean bret = false;
    
            for( ; index < size ; ){
    
                if( stack[index] < index ){
    
                    if( index %2 == 0 ){
                        swap(0, index);
                    }else{
                        swap(stack[index], index);
                    }
    
                    stack[index]++;           
                    index = 0;
                    bret = true;
                    break;
                }else{
                    stack[index] = 0;
                    index++;
                }
            }
    
            if( !bret ){
                // No more permutation available. 
                // Set the original array as return value.
                // Also set arr1 = null , so that hasNext() will return false for next test
                arr2 = arr1;
                arr1 = null;
            }
        }
    
        private void swap (final int i, final int j) {
            E temp = arr2[i];
            arr2[i] = arr2 [j];
            arr2[j] = temp;
        }
    }
    
    
    

    用法:

    
    public static void main(String[] args) {
    
            Permutator<Integer> perm = new Permutator<Integer>(new Integer[]{1,2,3, 4, 5});
            int count = 0;
            while(perm.hasNext()){
                System.out.println(Arrays.toString(perm.next()));
                count++;
            }
            System.out.println("total: " + count);
        }
    
    

    【讨论】:

      【解决方案3】:

      试试这个:

      import java.util.ArrayList;
      import java.util.Arrays;
      import java.util.Iterator;
      import java.util.List;
      import java.util.stream.IntStream;
      
      public class Paermulator {
      
          private final List<int[]> list = new ArrayList<>();
      
          public Paermulator(int i) {
              int[] array = IntStream.iterate(0, x -> x + 1)
                      .limit(i)
                      .toArray();
              populateList(array, 0);
          }
      
          private void populateList(int[] array, int index) {
              if (index >= array.length - 1) {
                  int[] temp = new int[array.length];
                  System.arraycopy(array, 0, temp, 0, array.length);
                  list.add(temp);
                  return;
              }
      
              for (int i = index; i < array.length; i++) {
                  int temp = array[index];
                  array[index] = array[i];
                  array[i] = temp;
      
                  populateList(array, index + 1);
      
                  temp = array[index];
                  array[index] = array[i];
                  array[i] = temp;
              }
          }
      
          public List<int[]> getList() {
              return list;
          }
      
          public Iterator<int []> getItrator() {
              return list.iterator();
          }
          // main method is for testing output
          public static void main(String[] args) {
              //printing output
              new Paermulator(5).getList().stream().forEach(x -> System.out.println(Arrays.toString(x)));
          }
      }
      

      该类在构造函数中接受一个 int 并创建一个数组并将该数组传递给populateList 方法此方法使用所有可能的排列填充列表。
      你可以使用getIterator方法得到Iterator

      【讨论】:

      • System.arraycopy()?它更快吗?
      • 它非常快,以确保它比其他方法更快或测试它有多快。
      • 它更快,但这不是你使用它的原因。您使用它是因为它更清晰。
      猜你喜欢
      • 1970-01-01
      • 2012-03-23
      • 2014-03-25
      • 2011-02-22
      • 1970-01-01
      • 2016-08-17
      • 2017-06-12
      • 2010-10-28
      • 1970-01-01
      相关资源
      最近更新 更多