C语言 next_permutation(数组排列)
c语言吧
全部回复
仅看楼主
level 9
redraiment 楼主
列出数组元素的所有排列是一项比较常用的功能。C++ 的 STL 库中自带了 next_permutation (很多其他高级语言也自带了类似功能),不过在纯 C 环境中就不得不自己实现了。算法描述如下:
对于排列,数组的初始状态是元素以升序排列;终止状态时元素以降序排列。比如 1 2 3 三个元素进行排列,最终状态会变成 3 2 1。这一性质也是递归的:即 1 2 3 这个序列,除去第一个元素 1,剩下 2 3 这个子序列,初始状态是 2 3、最终状态时 3 2。 当子序列到达最终状态时,前面的元素要进位(概念和数字进制进位类似)。上述例子中子序列到达 3 2 这个最终状态后,前面的元素是 1,此时要进位变成 2,子序列中的 2 变成 1(序列变成 2 3 1);最后,这个已经到达最终状态的子序列要恢复到初始状态(即反转:2 1 3)。
上述的算法思想虽然是“递归”,不过可以用迭代实现出来。下面是示例代码(贴吧现在好像不支持用   来输出空格,谁提供一个方法来保持代码格式整齐?):

2011年08月12日 06点08分 1
level 9
redraiment 楼主
/* 下面的代码我用全角空格,为的是保持代码格式,你们需要自己替换成两个半角空格 */
#include <stdlib.h>
#include <stdio.h>
#define swap(h, i) do { \
  int tmp = list[h]; \
  list[h] = list[i]; \
  list[i] = tmp; \
 } while(0)
typedef enum {
 false = 0,
 true = !false
} bool;
bool next_permutation(int list[], size_t size) {
 size_t head_item;
 size_t item;
 // find the sub completed list
 for (item = size - 1; item > 0; item--) {
  if (list[item - 1] < list[item]) {
   break;
  }
 }
 if (item == 0) {
  // finished
  return false;
 } else {
  head_item = item - 1;
 }
 // find the next item:
 // The first great than head_item
 for (item = size - 1; item > head_item; item--) {
  if (list[head_item] < list[item]) {
   break;
  }
 }
 swap(head_item, item);
 // reverse the sub list
 for (item = head_item + 1; item < size; item++, size--) {
  swap(item, size - 1);
 }
 return true;
}
int main(void)
{
 int list[] = {1, 2, 2, 4};
 do {
  printf("%d %d %d %d\n", list[0], list[1], list[2], list[3]);
 } while (next_permutation(list, sizeof(list) / sizeof(int)));
 return EXIT_SUCCESS;
}

2011年08月12日 06点08分 2
level 9
redraiment 楼主
运行结果:
routine$ gcc next_permutation.c -o main
routine$ ./main.exe
1 2 2 4
1 2 4 2
1 4 2 2
2 1 2 4
2 1 4 2
2 2 1 4
2 2 4 1
2 4 1 2
2 4 2 1
4 1 2 2
4 2 1 2
4 2 2 1
routine$ # 重复项自动处理
2011年08月12日 06点08分 3
level 9
redraiment 楼主
记得还有个递归算法,里面的重复元素会输出两次。
2011年08月12日 17点08分 4
level 15
先搞清楚C和C++是两门语言再说。[瞌睡]
2011年08月12日 20点08分 5
level 9
redraiment 楼主
回复5楼:
那请问您有哪里没搞清楚?
2011年08月12日 23点08分 6
level 15
好吧,我承认偷懒只看了标题…请无视。[拍砖]
2011年08月13日 00点08分 7
level 15
#include <stdio.h>
typedef enum
{
false = 0,
true = !false
} bool;
void
iter_swap(int* p, int* q)
{
int t = *p;
*p = *q;
*q = t;
}
void
reverse(int* first, int* last)
{
if (first == last)
return;
--last;
while (first < last)
{
iter_swap(first, last);
++first;
--last;
}
}
bool
next_permutation(int* first, int* last)
{
if(first == last)
return false;
int* p = first;
++p;
if (p == last)
return false;
p = last;
--p;
for(;;)
{
int* pi = p;
--p;
if (*p < *pi)
{
int* q = last;
while (!(*p < *--q))
;
iter_swap(p, q);
reverse(pi, last);
return true;
}
if (p == first)
{
reverse(first, last);
return false;
}
}
}
int main(void)
{
int list[] = {1, 2, 2, 4};
do {
printf("%d %d %d %d\n", list[0], list[1], list[2], list[3]);
} while (next_permutation(list, list + sizeof(list) / sizeof(int)));
getchar();
return 0;
}

2011年08月13日 00点08分 8
1