全排列生成算法

全排列生成算法

概述

​ 全排列問題,簡單來說,就是由n個不同元素組成的序列,從中取出n個元素,按不同順序排列起來。如:”123”,它的全排列爲,”123”,”132”,”213”,”231”,”312”,”321”,總共有n!種結果。

解法一:回溯法求解

​ 對於求解所有可能情況的問題,回溯法不失爲一種可以解決問題的方法。對於全排列生成,可以把序列的每一個字符作爲一層,也可以說是,固定一個字符,對剩餘的其他字符求解全排列,舉個例子:

“123”

固定1,求解”23”的全排列,與1組合,則是以1開頭的,所有可能的排列;

固定2,求解”13”的全排列,與2組合,則是以2開頭的,所有可能的排列;

固定3,求解”12”的全排列,與3組合,則是以3開頭的,所有可能的排列。

​ 當序列僅有一個元素時,全排列只有一種,是它本身。回溯法求全排列的過程,求解完固定一個字符的全排列之後,回溯到上層,再固定另一個求解的過程。

​ 具體代碼如下:

void cal_all_permutation(char *perm, int from, int to)
{
    if (to <= 1) {
        return;
    }

    if (from == to) {
        int i;
        for (i = 0; i <= to; ++i) {
            printf("%c", perm[i]);
        }
        printf("\n");
    }
    else {
        int i;
        for (i = from; i <= to; ++i) {
            std::swap(perm[i], perm[from]);
            cal_all_permutation(perm, from + 1, to);
            std::swap(perm[i], perm[from]);  //回溯過程
        }
    }
}

解法二:字典序排序

​ 字典序排序算是解決全排列生成問題的一種很好的方法,根據字符串各元素的字典序,可以確定兩個字符串的大小關係。

​ 這裏要先確定兩個前提:

  1. 字符串初始狀態必須經過升序排序;
  2. 字符串初始狀態是最小的一種排列。

​ 對於1,字典序排序解決全排列問題,核心思想是,在求解下一個排列時,下一個排列恰好比當前排列大,並且所求的下一個排列是比當前排列大的所有排列中最小的,當前序列變爲降序排序之後,就沒有比其更大的排列了,全排列所有情況求解得到。

​ 對於2,字典序確定兩個字符串大小時,是一次比較各個相應位置上的元素的大小,對於位置i, p1[i] > p2[i]則p1大於p2,同理,p1[i] < p2[i]則p1小於p2,僅有兩者字符完全相同的情況下才相等。因此,當初始狀態時,升序排序之後,任意字符串與其比較時,對於每個位置,並不可能再找出一個比初始狀態的該位置元素更小的元素(注意,排列問題中,各元素是不能重複的)。所以初始狀態必定爲最小排列。以下則是字典序排序具體描述:

字典序排序算法描述:

1. 從序列sz - 2位置開始(序列索引從0開始,末尾元素索引爲sz - 1),尋找第1個使得perm[i] < perm[i + 1]成立的元素,並記錄索引i;
2. 從序列sz - 1位置開始,在字典序大於perm[i]的元素中,尋找最小的那個元素,並記錄索引j;
3. 交換perm[i]與perm[j];
4. 反轉perm[i]至perm[sz - 1]之間的子序列,即i + 1 -> sz - 1。
bool cal_next_permutation(char *perm, int sz)
{
    int i;
    //尋找第1個使得perm[i] < perm[i + 1]成立的元素
    for (i = sz - 2; (i >= 0) && (perm[i] >= perm[i + 1]); --i) { 
        ;
    }

    //未找到,說明當前排列爲降序排序,不可能有更大的排列了
    if (i < 0) {
        return false;
    }

    int j;
    //尋找大於第一步中找到的元素的最小值
    for (j = sz - 1; (j > i) && (perm[j] <= perm[i]); --j) {
        ;
    }

    std::swap(perm[i], perm[j]);
    reverse(perm + i + 1, perm + sz);
    return true;
}
發佈了142 篇原創文章 · 獲贊 23 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章