c語言實現排列組合演算法問題

2021-07-01 18:10:02 字數 3669 閱讀 5516

排列組合是演算法常用的基本工具,如何在c語言中實現排列組合呢?思路如下:

首先看遞迴實現,由於遞迴將問題逐級分解,因此相對比較容易理解,但是需要消耗大量的棧空間,如果執行緒棧空間不夠,那麼就執行不下去了,而且函式呼叫開銷也比較大。

(1) 全排列:

全排列表示把集合中元素的所有按照一定的順序排列起來,使用p(n, n) = n!表示n個元素全排列的個數。

例如:的全排列為:

123;132;

213;231;

312;321;

共6個,即3!=321=6。

這個是怎麼算出來的呢?

首先取乙個元素,例如取出了1,那麼就還剩下。

然後再從剩下的集合中取出乙個元素,例如取出2,那麼還剩下。

以此類推,把所有可能的情況取一遍,就是全排列了,如圖:

知道了這個過程,演算法也就寫出來了:

將陣列看為乙個集合,將集合分為兩部分:0~s和s~e,其中0~s表示已經選出來的元素,而s~e表示還沒有選擇的元素。

perm

(set,s,e)

c語言**如下:

void

perm

(int

list

,ints,

inte

,void

(*cbk

)(int

list

))else

}}

其中:

void

swap

(int*o

,inti,

intj

)void

cbk_print

(int

*subs

)printf

("}\n"

);}

(2)組合:

組合指從n個不同元素中取出m個元素來合成的乙個組,這個組內元素沒有順序。使用c(n, k)表示從n個元素中取出k個元素的取法數。

c(n, k) = n! / (k! * (n-k)!)

例如:從中取出2個元素的組合為:

12;13

;14;23

;24;34

方法是:先從集合中取出乙個元素,例如取出1,則剩下

然後從剩下的集合中取出乙個元素,例如取出2

這時12就構成了乙個組,如圖。

從上面這個過程可以看出,每一次從集合中選出乙個元素,然後對剩餘的集合(n-1)進行一次k-1組合。

comb

(set

,subset,n,k)

c語言**如下:

void

combine

(ints,

intn

,intk,

void

(*cbk

)(int

*subset

,intk))

for(

inti =n

;i >=k;

i--)

else

}}

任何遞迴演算法都可以轉換為非遞迴演算法,只要使用乙個棧模擬函式呼叫過程中對引數的儲存就行了,當然,這樣的方法沒有多少意思,在這裡就不講了。下面要說的是用其它思路實現的非遞迴演算法:

(1)全排列:

首先來看一段**:

#include

#include

using

namespace

std;

intmain ();

cout

<<

"the 3! possible permutations with 3 elements:\n"

;sort

(myints

,myints+3

);do

while

(next_permutation

(myints

,myints+3

));return0;

}

這段**是從stl permutation上考下來的,要注意的是第10行,首先對陣列進行了排序。

第14行的next_permutation()是stl的函式,它的原理是這樣的:生成當前列表的下乙個相鄰的字典序列表,裡面的元素只能交換位置,數值不能改變。

什麼意思呢?

123的下乙個字典序是132,因為132比123大,但是又比其他的序列小。

演算法是:

(1) 從右向左,找出第乙個比右邊數字小的數字a。

(2) 從右向左,找出第乙個比a大的數字b。

(3) 交換a和b。

(4) 將a後面的串(不包括a)反轉。

就完成了。

好,現在按照上面的思路,寫出next_permutation函式:

template

<

class

t>

bool

next_perm(t

*start,t

*end)if

(start

==end

)else

else}if

(pa

==null

)// find b.

for(t *

p =end;

p >=

start;p

--)}

// swap a, b.

tmp =*

pa;*pa =*

pb;*pb

=tmp

;// flip sequence after a

for(t *

p =pa+

1,*q

=end;p

p++,

q--)

return

true;}

}

(2)組合:01交換法

使用0或1表示集合中的元素是否出現在選出的集合中,因此乙個0/1列表即可表示選出哪些元素。

例如:[1 2 3 4 5],選出的元素是[1 2 3]那麼列表就是[1 1 1 0 0]。

演算法是這樣的:

comb

(set,n,k)

**如下:

template

<

class

t>

void

combine(t

set,

intn

,intk,

void

(*cbk

)(t

set))

// begin scan.

bool

has_next

=true

;while

(has_next)}

cbk(

subset

);has_next

=false

;for

(inti =

0;i

1;i++)if(

count

for(

intj

=count;j

j++)

}has_next

=true

;break;}

}}delete

vec;

delete

subset

;}

至於其中的道理,n個位置上有k個1,按照演算法移動,可以保證k個1的位置不重複,且覆蓋n一遍。

c語言實現排列組合演算法問題

排列組合是演算法常用的基本工具,如何在c語言中實現排列組合呢?思路如下 首先看遞迴實現,由於遞迴將問題逐級分解,因此相對比較容易理解,但是需要消耗大量的棧空間,如果執行緒棧空間不夠,那麼就執行不下去了,而且函式呼叫開銷也比較大。1 全排列 全排列表示把集合中元素的所有按照一定的順序排列起來,使用p ...

排列組合演算法實現

全排列表示把集合中元素的所有按照一定的順序排列起來,使用p n,n n 表示n個元素全排列的個數。例如 的全排列為 123 132 213 231 312 321 共6個,即3!321 6。這個是怎麼算出來的呢?首先取乙個元素,例如取出了1,那麼就還剩下。然後再從剩下的集合中取出乙個元素,例如取出2...

c 排列組合演算法

combinatorics.cs 清單 usingsystem usingsystem.collections usingsystem.data 組合數學函式集 publicclasscombinatorics returndt 連乘積函式 publicstaticintproduct intsta...