首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

java 排列组合有关问题汇总

2012-11-25 
java 排列组合问题汇总组合算法实现从m个数里面取n个数的算法。最容易理解的就是递归,但是其效率太低。实现

java 排列组合问题汇总

组合算法实现

从m个数里面取n个数的算法。最容易理解的就是递归,但是其效率太低。

实现方法一:

// 组合算法
// 本程序的思路是开一个数组,其下标表示1到m个数,数组元素的值为1表示其下标
// 代表的数被选中,为0则没选中。
// 首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。
// 然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为
// “01”组合,同时将其左边的所有“1”全部移动到数组的最左端。
// 当第一个“1”移动到数组的m-n的位置,即n个“1”全部移动到最右端时,就得
// 到了最后一个组合。
// 例如求5中选3的组合:
// 1 1 1 0 0 //1,2,3
// 1 1 0 1 0 //1,2,4
// 1 0 1 1 0 //1,3,4
// 0 1 1 1 0 //2,3,4
// 1 1 0 0 1 //1,2,5
// 1 0 1 0 1 //1,3,5
// 0 1 1 0 1 //2,3,5
// 1 0 0 1 1 //1,4,5
// 0 1 0 1 1 //2,4,5
// 0 0 1 1 1 //3,4,5

import java.util.ArrayList;
import java.util.List;

/**
* 面试中遇到的问题,在网上查找资料,加上自己的总结, java 代码实现组合的算法
* 从n个数里取出m个数的组合是n*(n-1)*...*(n-m+1)/m*(m-1)*...2*1 该方法比较好理解,但具体算法的分析却有难度。
*
* @date

* @Java教程:http://www.javaweb.cc

*
*/
class Zuhe1 {

/**
* @param a:组合数组
* @param k:生成组合个数
* @return :所有可能的组合数组列表
*/
private List zuhe(int[] a, int m) {
Zuhe1 zuhe = new Zuhe1();
List list = new ArrayList();
int n = a.length;

boolean flag = false; // 是否是最后一种组合的标记

// 生成辅助数组。首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。
int[] tempNum = new int[n];
for (int i = 0; i < n; i++) {
if (i < m) {
tempNum[i] = 1;

} else {
tempNum[i] = 0;
}
System.out.print(tempNum[i]);
}
print(tempNum);// 打印辅助数组

list.add(zuhe.createResult(a, tempNum, m));// 打印第一中默认组合

do {
int pose = 0; // 记录改变的位置
int sum = 0; // 记录改变位置 左侧 1 的个数
// 然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为“01”
for (int i = 0; i < (n - 1); i++) {
if (tempNum[i] == 1 && tempNum[i + 1] == 0) {
tempNum[i] = 0;
tempNum[i + 1] = 1;
pose = i;
break;
}
}
print(tempNum);// 打印辅助数组
list.add(zuhe.createResult(a, tempNum, m));// 打印第一中默认组合

// 同时将其左边的所有“1”全部移动到数组的最左端。

for (int i = 0; i < pose; i++) {
if (tempNum[i] == 1)
sum++;
}

for (int i = 0; i < pose; i++) {
if (i < sum)
tempNum[i] = 1;
else
tempNum[i] = 0;
}

// 判断是否为最后一个组合:当第一个“1”移动到数组的m-n的位置,即n个“1”全部移动到最右端时,就得到了最后一个组合。
flag = false;
for (int i = n - m; i < n; i++) {

if (tempNum[i] == 0)
flag = true;

}
} while (flag);

return list;
}

// 根据辅助数组和原始数组生成 结果数组
public int[] createResult(int[] a, int[] temp, int m) {
int[] result = new int[m];

int j = 0;
for (int i = 0; i < a.length; i++) {

if (temp[i] == 1) {
result[j] = a[i];
System.out.println("result[" + j + "]:" + result[j]);
j++;

}
}

return result;
}

// 打印
public void print1(List list) {

for (int i = 0; i < list.size(); i++) {
System.out.println();
int[] temp = (int[]) list.get(i);
for (int j = 0; j < temp.length; j++) {
System.out.print(temp[j] + " ");
}
}
}

// 打印整数数组的方法
public void print(int[] a) {
System.out.println("生成的辅助数组为:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]);
}
System.out.println();
}

public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5 }; // 整数数组
int m = 3; // 待取出组合的个数
Zuhe1 zuhe = new Zuhe1();
List list = zuhe.zuhe(a, m);
zuhe.print1(list);

}
}

 

解决这类问题,用for循环嵌套是不现实的(只能对指定的m、n编程,而且程序看上去异常繁琐),较好的方法是回朔法。下面给出这类问题的一般算法的c/c++描述:

int combine(int a[],int sub){
//a[1..?]表示候选集,sub表示一个排列(组合)的元素个数
{
   int total=sizeof(a);
   int order[sub+1];
   int count=0;//符合条件的排列(组合)的个数
   order[0]=-1;
   for(int i=1;i<=sub;i++)
      order[i]=i;
   int k=sub;
   bool flag=true;
   while(order[0]!=-1){
      if(flag){
         for(i=1;i<=sub;i++)//输出符合要求的组合
            printf("%d ",a[order[i]]);
         printf("\n");
         count++;
         flag=false;
      }
      order[k]++;
      if(order[k]==total+1){
         order[k--]=0;
         continue;
      }   
   ...
      //在此加入order[k]的限制条件
      //如果条件满足,则往下执行
      //否则continue;
      if(k<sub){
         order[++k]=order[k-1];
         continue;
      }
      if(k==sub)
         flag=true;
   }
   return count;
}

 

 

 

// permutation.h : List all the permutation subsets of a certian set.
java 排列组合有关问题汇总//
java 排列组合有关问题汇总
java 排列组合有关问题汇总#pragma once
java 排列组合有关问题汇总
java 排列组合有关问题汇总#include <iostream>
java 排列组合有关问题汇总#include <iomanip>
java 排列组合有关问题汇总using namespace std;
java 排列组合有关问题汇总
java 排列组合有关问题汇总// Compute P(N, M). N is the total number, M is the selected number.
java 排列组合有关问题汇总template<int N, int M>
java 排列组合有关问题汇总class CPermutation
java 排列组合有关问题汇总{
java 排列组合有关问题汇总private:
java 排列组合有关问题汇总    int** m_result; // two-dimension array of [m_nCount][M]
java 排列组合有关问题汇总    int m_nCount; // how many results
java 排列组合有关问题汇总    int m_nIndex; // 0 - m_nCount - 1
java 排列组合有关问题汇总
java 排列组合有关问题汇总public:
java 排列组合有关问题汇总    // List all possible results by nesting
java 排列组合有关问题汇总    void Count()
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        m_nIndex = 0;
java 排列组合有关问题汇总        int result[N], used[N];
java 排列组合有关问题汇总        for (int i = 0; i < N; i++)
java 排列组合有关问题汇总            used[i] = 0;
java 排列组合有关问题汇总        CountRecur(result, used, 0);
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    void CountRecur(int result[M], int used[M], int i)
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        for (int k = 0; k < N; k++)
java 排列组合有关问题汇总        {
java 排列组合有关问题汇总            if (used[k])
java 排列组合有关问题汇总                continue ;
java 排列组合有关问题汇总
java 排列组合有关问题汇总            result[i] = k;
java 排列组合有关问题汇总            used[k] = 1;
java 排列组合有关问题汇总            if (i < M - 1)
java 排列组合有关问题汇总                CountRecur(result, used, i + 1);
java 排列组合有关问题汇总            else
java 排列组合有关问题汇总                Add(result);
java 排列组合有关问题汇总            used[k] = 0;
java 排列组合有关问题汇总        }
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Save the result
java 排列组合有关问题汇总    void Add(int sz[M])
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        memcpy(m_result[m_nIndex], sz, M * sizeof(int));
java 排列组合有关问题汇总        ++m_nIndex;
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Count the number of subsets
java 排列组合有关问题汇总    // C(N, M) = N! / ((N - M)! * M!)
java 排列组合有关问题汇总    static int NumberOfResult()
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        if (N <= 0 || M <= 0 || M > N)
java 排列组合有关问题汇总            return 0;
java 排列组合有关问题汇总        int result = 1;
java 排列组合有关问题汇总        for (int i = 0; i < M; i++)
java 排列组合有关问题汇总            result *= N - i;
java 排列组合有关问题汇总        return result;
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Print them to the standard output device
java 排列组合有关问题汇总    void Print()
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        for (int i = 0; i < m_nCount; i++)
java 排列组合有关问题汇总        {
java 排列组合有关问题汇总            cout << setw(3) << setfill(' ') << i + 1 << ":";
java 排列组合有关问题汇总            for (int j = 0; j < M; j++)
java 排列组合有关问题汇总                cout << setw(3) << setfill(' ') << m_result[i][j] + 1;
java 排列组合有关问题汇总            cout << endl;
java 排列组合有关问题汇总        }
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    CPermutation()
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        // allocate memories for the result
java 排列组合有关问题汇总        m_nCount = NumberOfResult();
java 排列组合有关问题汇总        m_result = new int*[m_nCount];
java 排列组合有关问题汇总        for (int i = 0; i < m_nCount; i++)
java 排列组合有关问题汇总            m_result[i] = new int[M];
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总    ~CPermutation()
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        // deallocate memories for the result
java 排列组合有关问题汇总        for (int i = 0; i < m_nCount; i++)
java 排列组合有关问题汇总            delete[] m_result[i];
java 排列组合有关问题汇总        delete[] m_result;
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总};
java 排列组合有关问题汇总


问题2:从N个元素中选择M个元素进行组合,列出所有结果。
与排列不同的是,组合不需要对选择出来的M个元素进行排列,不妨假定每一组结果中的M个元素从小到大排列。

java 排列组合有关问题汇总// combination.h : list all the subsets of a certian set
java 排列组合有关问题汇总//
java 排列组合有关问题汇总
java 排列组合有关问题汇总#pragma once
java 排列组合有关问题汇总
java 排列组合有关问题汇总#include <iostream>
java 排列组合有关问题汇总#include <iomanip>
java 排列组合有关问题汇总using namespace std;
java 排列组合有关问题汇总
java 排列组合有关问题汇总// List all the M-subsets of the N-set
java 排列组合有关问题汇总template<int N, int M>
java 排列组合有关问题汇总class CCombination
java 排列组合有关问题汇总{
java 排列组合有关问题汇总private:
java 排列组合有关问题汇总    int** m_result; // two-dimension array of m_nCount * M
java 排列组合有关问题汇总    int m_nCount; // how many results of M-length array
java 排列组合有关问题汇总
java 排列组合有关问题汇总public:
java 排列组合有关问题汇总    CCombination()
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        // allocate memories for the result
java 排列组合有关问题汇总        m_nCount = NumberOfResult();
java 排列组合有关问题汇总        m_result = new int*[m_nCount];
java 排列组合有关问题汇总        for (int i = 0; i < m_nCount; i++)
java 排列组合有关问题汇总            m_result[i] = new int[M];
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总    ~CCombination()
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        // deallocate memories for the result
java 排列组合有关问题汇总        for (int i = 0; i < m_nCount; i++)
java 排列组合有关问题汇总            delete[] m_result[i];
java 排列组合有关问题汇总        delete[] m_result;
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // process of counting
java 排列组合有关问题汇总    void Count()
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        int sz[M];
java 排列组合有关问题汇总        int nResultCount = 0;
java 排列组合有关问题汇总        CountRecur(sz, 0, 0, nResultCount);
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Print them to the standard output device
java 排列组合有关问题汇总    void Print()
java 排列组合有关问题汇总    { 
java 排列组合有关问题汇总        using std::cout;
java 排列组合有关问题汇总        using std::setw;
java 排列组合有关问题汇总        using std::setfill;
java 排列组合有关问题汇总        using std::endl;
java 排列组合有关问题汇总
java 排列组合有关问题汇总        for (int i = 0; i < m_nCount; i++)
java 排列组合有关问题汇总        {
java 排列组合有关问题汇总            cout << setw(3) << setfill(' ') << i + 1 << ":";
java 排列组合有关问题汇总            for (int j = 0; j < M; j++)
java 排列组合有关问题汇总                cout << setw(3) << setfill(' ') << m_result[i][j] + 1;
java 排列组合有关问题汇总            cout << endl;
java 排列组合有关问题汇总        }
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总private:
java 排列组合有关问题汇总    // Count the number of subsets
java 排列组合有关问题汇总    // C(N, M) = N! / ((N - M)! * M!)
java 排列组合有关问题汇总    int NumberOfResult()
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        int result = 1;
java 排列组合有关问题汇总        for (int i = 0; i < M; i++)
java 排列组合有关问题汇总            result *= N - i;
java 排列组合有关问题汇总        for (int j = 1; j <= M; j++)
java 排列组合有关问题汇总            result /= j;
java 排列组合有关问题汇总        return result;
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Get the current value
java 排列组合有关问题汇总    // sz - array of the current result
java 排列组合有关问题汇总    // nIndex - index of sz, 0 <= nIndex < M
java 排列组合有关问题汇总    // nStartVal - the current minimum value, 0 <= nStartVal < N
java 排列组合有关问题汇总    // nResultCount - index of m_result
java 排列组合有关问题汇总    void CountRecur(int sz[M], int nIndex, int nStartVal, int& nResultCount)
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        if (nStartVal + M - nIndex > N)
java 排列组合有关问题汇总            return ;
java 排列组合有关问题汇总
java 排列组合有关问题汇总        for (int i = nStartVal; i < N; i++)
java 排列组合有关问题汇总        {
java 排列组合有关问题汇总            sz[nIndex] = i;
java 排列组合有关问题汇总            if (nIndex == M - 1)
java 排列组合有关问题汇总                Add(sz, nResultCount);
java 排列组合有关问题汇总            else
java 排列组合有关问题汇总                CountRecur(sz, nIndex + 1, i + 1, nResultCount);
java 排列组合有关问题汇总        }
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Save the result
java 排列组合有关问题汇总    void Add(int* sz, int& nIndex)
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        memcpy(m_result[nIndex], sz, M * sizeof(int));
java 排列组合有关问题汇总        ++nIndex;
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总};
java 排列组合有关问题汇总


当然,如果将回溯法运用到工程中去,正确性只是必要条件之一,效率显得相当重要,高效的界定代码则是其中的关键。甚至可以考虑换一种方法来实现,当然回溯的思想应该都一样。下面一段代码实现N的阶乘(排列的一个特例),是我在工程中的一个应用。思路则是假设我们已经按照一种方式列出了所有结果
1, 2, 3
1, 3, 2
2, 1, 3
2, 3, 1
3, 1, 2
3, 2, 1
然后纵向的填写所有结果至结果数组中。

java 排列组合有关问题汇总// pi : this algorith lists all the sequences of a certian array
java 排列组合有关问题汇总//
java 排列组合有关问题汇总
java 排列组合有关问题汇总#pragma once
java 排列组合有关问题汇总
java 排列组合有关问题汇总#include "common.h"
java 排列组合有关问题汇总
java 排列组合有关问题汇总// how many sequence for N cells
java 排列组合有关问题汇总int NumberOfPI(int N)
java 排列组合有关问题汇总{
java 排列组合有关问题汇总    if (N < 0)
java 排列组合有关问题汇总        return 0;
java 排列组合有关问题汇总
java 排列组合有关问题汇总    if (N == 0)
java 排列组合有关问题汇总        return 1;
java 排列组合有关问题汇总
java 排列组合有关问题汇总    int pi = 1;
java 排列组合有关问题汇总    for (int i = 1; i <= N; i++)
java 排列组合有关问题汇总        pi *= i;
java 排列组合有关问题汇总
java 排列组合有关问题汇总    return pi;
java 排列组合有关问题汇总}
java 排列组合有关问题汇总
java 排列组合有关问题汇总// print all the sequence to a certain array
java 排列组合有关问题汇总// N - number of cells
java 排列组合有关问题汇总// PI - array of cells
java 排列组合有关问题汇总// selPI - index of array with initial value of 0 and maximum value of N - 1
java 排列组合有关问题汇总// Index - result array
java 排列组合有关问题汇总// selIndex - number of result array
java 排列组合有关问题汇总void PrintPI(int N, int* PI, int selPI, int** Index, int selIndex)
java 排列组合有关问题汇总{
java 排列组合有关问题汇总    if (N <= 0)
java 排列组合有关问题汇总        return ;
java 排列组合有关问题汇总
java 排列组合有关问题汇总    int num = NumberOfPI(N - selPI - 1);
java 排列组合有关问题汇总    for (int i = selPI; i < N; i++)
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        swap(PI[selPI], PI[i]);
java 排列组合有关问题汇总        PrintPI(N, PI, selPI + 1, Index, selIndex);
java 排列组合有关问题汇总        for (int j = 0; j < num; j++)
java 排列组合有关问题汇总            Index[selIndex++][selPI] = PI[selPI];
java 排列组合有关问题汇总        swap(PI[selPI], PI[i]);
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总}
java 排列组合有关问题汇总
java 排列组合有关问题汇总int PrintPITest()
java 排列组合有关问题汇总{
java 排列组合有关问题汇总    // Number
java 排列组合有关问题汇总    static const int N = 5;
java 排列组合有关问题汇总    
java 排列组合有关问题汇总    // Result in all sequences
java 排列组合有关问题汇总    int PI[N];
java 排列组合有关问题汇总    for (int l = 0; l < N; l++)
java 排列组合有关问题汇总        PI[l] = l + 1;
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Allocate the two_demension array
java 排列组合有关问题汇总    const int num = NumberOfPI(N);
java 排列组合有关问题汇总    int **Index;
java 排列组合有关问题汇总    Index = new int*[num];
java 排列组合有关问题汇总    for (int l = 0; l < num; l++)
java 排列组合有关问题汇总        Index[l] = new int[N];
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Calculating.
java 排列组合有关问题汇总    PrintPI(N, PI, 0, Index, 0);
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Print it to cout
java 排列组合有关问题汇总    for (int i = 0; i < num; i++)
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        printf("%5d : ", i + 1);
java 排列组合有关问题汇总        for (int j = 0; j < N; j++)
java 排列组合有关问题汇总            printf("%2d ", Index[i][j]);
java 排列组合有关问题汇总        printf("/n");
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Check if there is any identical indexes.
java 排列组合有关问题汇总    for (int i = 0; i < num - 1; i++)
java 排列组合有关问题汇总    for (int j = i + 1; j < num; j++)
java 排列组合有关问题汇总    {
java 排列组合有关问题汇总        int k = 0;
java 排列组合有关问题汇总        for (; k < N; k++)
java 排列组合有关问题汇总            if (Index[i][k] != Index[j][k])
java 排列组合有关问题汇总                break;
java 排列组合有关问题汇总        if (k == N)
java 排列组合有关问题汇总            printf("Check ERROR!/n");
java 排列组合有关问题汇总    }
java 排列组合有关问题汇总
java 排列组合有关问题汇总    // Release the two_demension array
java 排列组合有关问题汇总    for (int l = 0; l < num; l++)
java 排列组合有关问题汇总        delete[] Index[l];
java 排列组合有关问题汇总    delete[] Index;
java 排列组合有关问题汇总
java 排列组合有关问题汇总    return 0;
java 排列组合有关问题汇总}
java 排列组合有关问题汇总


事实上,如果你在工程应用中用到的只是可列举的排列组合结果,你应该考虑把结果直接编码到程序中去,这样最快了,只是扩展性不好罢了。

 

热点排行