Java implements an algorithm for finding all combinations of k elements in an array

 

Given an array of size N, for example e={'A','B','C','D','E'} N = 5 , we want to find all possible combinations of k elements in the array . For example, if k = 3, one possible combination is {'A','B','C'}. Here, we have three different algorithms to find k combinations of the array .

Forward-backward algorithm

Here, we have two arrays and two main indexes r & i :

  • Array e is an array of elements.
  • Array pointer , the array pointer is used to save the index of the selected element.
  • The index i points to the currently selected element in the array e .
  • Point to the index r of the current position in the pointer array .
  • As long as i & r does not exceed the length of the array, the algorithm will move forward by increasing i & r .
  • If r reaches the last position of the pointer array, a combination will be printed.
  • If these two indices reach the last poisition of the array it points to, the algorithm will regress by reducing the [R value r--, and set the value I used i = pointer[r]+1.

groups_forwardbackward

public static void combination(Object[]  elements, int k){
       
       

	// get the length of the array
	// e.g. for {'A','B','C','D'} => N = 4 
	int N = elements.length;
	
	if(k > N){
       
       
		System.out.println("Invalid input, K > N");
		return;
	}
		
	// init combination index array
	int pointers[] = new int[k];
	

	int r = 0; // index for combination array
	int i = 0; // index for elements array
	
	while(r >= 0){
       
       
	
		// forward step if i < (N + (r-K))
		if(i <= (N + (r - k))){
       
       
			pointers[r] = i;
				
			// if combination array is full print and increment i;
			if(r == k-1){
       
       
				print(pointers, elements);
				i++;				
			}
			else{
       
       
				// if combination is not full yet, select next element
				i = pointers[r]+1;
				r++;										
			}				
		}
		
		// backward step
		else{
       
       
			r--;
			if(r >= 0)
				i = pointers[r]+1;
			
		}			
	}
}

Shift algorithm

  • This algorithm is more intuitive than the first algorithm.
  • We actually divide the elements array into two types of elements: k elements that can be selected and Nk elements that will be ignored.
  • In each iteration, we select Nk non-ignorable elements.
  • After each iteration, we will ignore the position movement of the element, as shown in the figure below.

groups_shifting

public static void combination(Object[]  e, int k){
       
       

	int[] ignore = new int[e.length-k]; // --> [0][0]
	int[] combination = new int[k]; // --> [][][]
	
	// set initial ignored elements 
	//(last k elements will be ignored)
	for(int w = 0; w < ignore.length; w++)
		ignore[w] = e.length - k +(w+1);
	
	int i = 0, r = 0, g = 0;
	
	boolean terminate = false;
	while(!terminate){
       
          
		
		// selecting N-k non-ignored elements
		while(i < e.length && r < k){
       
       
    			
    		if(i != ignore[g]){
       
       
    			combination[r] = i;
    			r++; i++;
    		}
    		else{
       
       	    			
    			if(g != ignore.length-1)
    				g++;	    			
    			i++;
    		}
    	}
    	print(combination, e);
    	i = 0; r = 0; g = 0;

    	terminate = true;
    	
    	// shifting ignored indices
    	for(int w = 0 ; w < ignore.length; w++){
       
       
    		if(ignore[w] > w){
       
       	    			
    			ignore[w]--;
    			
    			if(w > 0)
    				ignore[w-1] = ignore[w]-1;
    			terminate = false;
    			break;	    			
    		}
    	}
	}    		
}

Recursive algorithm

  • The recursive algorithm has shorter steps.
  • In each call to the function, we pass a list of elements, k and cumulative combination.
  • Then we have four conditions:
    1. If elements.length < kthen stop
    2. If k == 1then add each element to the cumulative combination
    3. If it is, elements.length == kall elements are added to the cumulative combination.
    4. If it is, a recursive call elements.length > kis made to each element eto pass a sublist of the element list, k-1and then the element is added eto the accumulated combination.
  • As shown below

groups_recursive

public static void combination(List<String> e, int k, String accumulated){
       
       

	// 1. stop
	if(e.size() < k)
		return;
	
	// 2. add each element in e to accumulated
	if(k == 1)
		for(String s:e)
			print(accumulated+s);
	
	// 3. add all elements in e to accumulated
	else if(e.size() == k){
       
       
		for(String s:e)
			accumulated+=s;
		print(accumulated);
	}
	
	// 4. for each element, call combination
	else if(e.size() > k)
		for(int i = 0 ; i < e.size() ; i++)
			combination(e.subList(i+1, e.size()), k-1, accumulated+e.get(i));
	
}

Source code @  GitHub

 
 

Guess you like

Origin blog.csdn.net/allway2/article/details/114898722