亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#算法之全排列遞歸算法實例講解

2020-01-24 02:19:49
字體:
來源:轉載
供稿:網友

排列:從n個元素中任取m個元素,并按照一定的順序進行排列,稱為排列;

全排列:當n==m時,稱為全排列;

比如:集合{ 1,2,3}的全排列為:

復制代碼 代碼如下:

{ 1 2 3}
{ 1 3 2 }
{ 2 1 3 }
{ 2 3 1 }
{ 3 2 1 }
{ 3 1 2 }

我們可以將這個排列問題畫成圖形表示,即排列枚舉樹,比如下圖為{1,2,3}的排列枚舉樹,此樹和我們這里介紹的算法完全一致;

算法思路:

(1)n個元素的全排列=(n-1個元素的全排列)+(另一個元素作為前綴);

(2)出口:如果只有一個元素的全排列,則說明已經排完,則輸出數組;

(3)不斷將每個元素放作第一個元素,然后將這個元素作為前綴,并將其余元素繼續全排列,等到出口,出口出去后還需要還原數組;

這里先把集合中的元素理解為不會出現重復了,那么實現的方法(C++)如下:

復制代碼 代碼如下:

成員管理,互評,文件共享,事務通知
#include <iostream>
using namespace std;

int sum = 0;//記錄有多少種組合

void Swap(char str[], int a, int b)
{
    char temp = str[a];
    str[a] = str[b];
    str[b] = temp;
}

void Perm(char str[], int begin, int end)
{
    if (begin == end)
    {
        for (int i = 0; i <= end; i++)
        {
            cout << str[i];
        }
        cout << endl;
        sum++;
        return;
    }
    else
    {
        for (int j = begin; j <= end; j++)
        {
            Swap(str, begin, j);
            Perm(str, begin + 1, end);
            Swap(str, j, begin);
        }
    }
}

int main()
{
    int n;
    char c[16];
    char tmp;


    cin >> n;
    tmp = getchar();    // 接受回車
    if (1 <= n && n <= 15) {
        for (int i = 0; i < n; i++) {
            c[i] = getchar();
        }
        Perm(c, 0, n - 1);
    }
    cout << sum;
    cout << endl;
    return 0;
}

實現后效果如下圖:

有重復元素的排列問題

然后現在的題目要求是排列中的元素是包含相同元素的,給定n以及待排的n個可能重復的元素。計算輸出n個元素的所有不同排列,因此上面那個算法顯然還是不夠好,因為相同的元素都當成不同的元素,因此有了重復的排列在里面

去掉重復符號的全排列:在交換之前可以先判斷兩個符號是否相同,不相同才交換,這個時候需要一個判斷符號是否相同的函數。也就是下面的IsSwap();

對122,第一個數1與第二個數2交換得到212,然后考慮第一個數1與第三個數2交換,此時由于第三個數等于第二個數,所以第一個數不再與第三個數交換。再考慮212,它的第二個數與第三個數交換可以得到解決221。

去掉重復的規則:去重的全排列就是從第一個數字起每個數分別與它后面非重復出現的數字交換。

復制代碼 代碼如下:

#include <iostream>
using namespace std;

int sum=0;//記錄有多少種組合

void Swap(char str[], int a, int b)
{
    char temp = str[a];
    str[a] = str[b];
    str[b] = temp;
}

bool IsSwap(char *pchar, int nBegin, int nEnd)
{
    for (int i = nBegin; i < nEnd; i++)
        if (pchar[i] == pchar[nEnd])
            return false;
    return true;
}

void Perm(char str[], int begin, int end)
{
    if (begin==end)
    {
        for (int i = 0; i <= end; i++)
        {
            cout << str[i];
        }
        cout << endl;
        sum++;
        return;
    }
    else
    {
        for (int j = begin; j <= end; j++)
        {
            if (IsSwap(str, begin, j))
            {
                Swap(str, begin, j);
                Perm(str, begin + 1, end);
                Swap(str, j, begin);
            }
        }
    }
}

int main()
{
    int n;
    char c[16];
    char tmp;


    cin >> n;
    tmp = getchar();    // 接受回車
    if (1 <= n && n <= 15) {
        for (int i = 0; i < n; i++) {
            c[i] = getchar();
        }
        Perm(c, 0, n - 1);
    }
    cout << sum;
    cout << endl;
    return 0;
}

非遞歸的實現

實現思路:

要考慮全排列的非遞歸實現,先來考慮如何計算字符串的下一個排列。如"1234"的下一個排列就是"1243"。只要對字符串反復求出下一個排列,全排列的也就迎刃而解了。

如何計算字符串的下一個排列了?來考慮"926520"這個字符串,我們從后向前找第一雙相鄰的遞增數字,"20"、"52"都是非遞增的,"26 "即滿足要求,稱前一個數字2為替換數,替換數的下標稱為替換點,再從后面找一個比替換數大的最小數(這個數必然存在),0、2都不行,5可以,將5和2交換得到"956220",然后再將替換點后的字符串"6220"顛倒即得到"950226"。

對于像"4321"這種已經是最“大”的排列,采用STL中的處理方法,將字符串整個顛倒得到最“小”的排列"1234"并返回false。

復制代碼 代碼如下:

//全排列的非遞歸實現
#include <iostream>
using namespace std;
void Swap(char *a, char *b)
{
    char t = *a;
    *a = *b;
    *b = t;
}
//反轉區間
void Reverse(char *a, char *b)
{
    while (a < b)
        Swap(a++, b--);
}
//下一個排列
bool Next_permutation(char a[])
{
    char *pEnd = a + strlen(a);
    if (a == pEnd)
        return false;
    char *p, *q, *pFind;
    pEnd--;
    p = pEnd;
    while (p != a)
    {
        q = p;
        --p;
        if (*p < *q) //找降序的相鄰2數,前一個數即替換數
        {
            //從后向前找比替換點大的第一個數
            pFind = pEnd;
            while (*pFind <= *p)
                --pFind;
            //替換
            Swap(pFind, p);
            //替換點后的數全部反轉
            Reverse(q, pEnd);
            return true;
        }
    }
    Reverse(p, pEnd);//如果沒有下一個排列,全部反轉后返回true
    return false;
}
int QsortCmp(const void *pa, const void *pb)
{
    return *(char*)pa - *(char*)pb;
}
int main()
{
    int sum = 0;
    char szTextStr[16];
    cin >> szTextStr;
    char tmp = getchar();    // 接受回車
   
    //加上排序
    qsort(szTextStr, strlen(szTextStr), sizeof(szTextStr[0]), QsortCmp);
    int i = 1;
    cout << endl << endl << endl;
    do{
        cout<<szTextStr<<endl;
        sum++;
    } while (Next_permutation(szTextStr));

    cout << sum<<endl;
    return 0;
}

總結:

排列在筆試面試中很熱門,在百度和迅雷的校園招聘以及程序員和軟件設計師的考試中都考到了,因此了解全排列算法對我們都很有好處。也是算法的一個基本思想。遞歸算法的思路比較直,而非遞歸的就比較難去想到使用這種方法來實現。

1.全排列就是從第一個數字起每個數分別與它后面的數字交換。

2.去重的全排列就是從第一個數字起每個數分別與它后面非重復出現的數字交換。

3.全排列的非遞歸就是由后向前找替換數和替換點,然后由后向前找第一個比替換數大的數與替換數交換,最后顛倒替換點后的所有數據。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美性高潮床叫视频| 久久天天躁日日躁| 国产美女扒开尿口久久久| 亚州成人av在线| 国产欧美在线视频| 亚洲欧美中文字幕在线一区| 成人网在线观看| 九色精品免费永久在线| 亚洲伊人久久大香线蕉av| 91久久久久久久久久久| 亚洲最新av在线网站| 国产精品九九久久久久久久| 欧美人交a欧美精品| 精品国产一区二区三区久久狼黑人| 日本久久91av| 国产91露脸中文字幕在线| 欧美精品www| 一本色道久久88精品综合| 欧美成人一区在线| 亚洲欧洲日产国码av系列天堂| 欧美日韩成人免费| 欧美在线视频观看免费网站| 国产在线视频欧美| 国产福利精品在线| 欧美高清电影在线看| 欧美另类在线播放| 亚洲成人黄色在线| 国产ts人妖一区二区三区| 91九色蝌蚪国产| 成人精品视频久久久久| 国产脚交av在线一区二区| 亚洲有声小说3d| 7777免费精品视频| 久久精品久久久久久国产 免费| 欧美高清在线观看| 久久成人人人人精品欧| 午夜精品福利视频| 国产成人午夜视频网址| 亚洲精品一区二区三区不| 欧洲中文字幕国产精品| 日本在线观看天堂男亚洲| 日韩有码视频在线| 最近2019中文字幕大全第二页| 国产精品第一第二| 98精品国产高清在线xxxx天堂| 欧美乱妇高清无乱码| 亚洲a级在线观看| 91国在线精品国内播放| 亚洲欧美在线x视频| 日本精品性网站在线观看| 亚洲男人天堂2024| 国产成人精品在线视频| 97超碰国产精品女人人人爽| 最近2019中文免费高清视频观看www99| 91精品国产色综合久久不卡98| 亚洲精品丝袜日韩| 亚洲欧美国产一本综合首页| 中文字幕亚洲综合| 日韩av电影免费观看高清| 亚洲免费精彩视频| 亚洲电影在线看| 亚洲午夜精品久久久久久性色| 久久久国产91| 欧美精品videosex牲欧美| 亚洲欧美另类在线观看| 欧美成人亚洲成人日韩成人| 欧美综合在线观看| 久热国产精品视频| 亚洲国产欧美日韩精品| 亚洲精品福利免费在线观看| 国产精品欧美风情| 日韩精品免费综合视频在线播放| 午夜伦理精品一区| 美乳少妇欧美精品| 欧美尤物巨大精品爽| 国产中文字幕亚洲| 国产精品欧美一区二区三区奶水| 国产一区二区三区四区福利| 欧美日本啪啪无遮挡网站| 国产精品一区二区三区成人| 亚洲free性xxxx护士hd| 日韩av免费网站| 欧美第一淫aaasss性| 久久久久久久久亚洲| 亚洲自拍偷拍在线| 日韩天堂在线视频| 在线观看免费高清视频97| 日韩黄色高清视频| 国产精品ⅴa在线观看h| 97国产suv精品一区二区62| 欧美日韩精品国产| 亚洲欧洲高清在线| 欧美日韩国产黄| 欧美国产欧美亚洲国产日韩mv天天看完整| 国产精品一区二区久久| 日韩精品免费一线在线观看| 国产91久久婷婷一区二区| 亚洲国产精品久久91精品| 91国在线精品国内播放| 亚洲人a成www在线影院| 欧美激情乱人伦一区| 4444欧美成人kkkk| 亚洲一区久久久| 亚洲系列中文字幕| 精品视频在线导航| 国产精品手机播放| 97精品伊人久久久大香线蕉| 97在线观看视频| 国产精品无av码在线观看| 狠狠久久亚洲欧美专区| 69av视频在线播放| 98精品国产自产在线观看| 国产精品视频在线播放| 欧美日韩国产成人高清视频| 欧美日韩亚洲一区二区三区| 在线视频日韩精品| 91欧美精品成人综合在线观看| 精品国产91乱高清在线观看| 日韩欧美在线观看| 国产欧美va欧美va香蕉在线| 国产成人亚洲综合| 亚洲黄色在线看| 欧美国产视频一区二区| 国产成人久久久精品一区| 国产99久久精品一区二区永久免费| 亚洲欧美国产另类| 韩剧1988免费观看全集| 黑丝美女久久久| 亚洲精品小视频| 欧美极品少妇与黑人| 91网在线免费观看| 久久久久久久久中文字幕| 久久99久久亚洲国产| 国产成人在线视频| 日韩精品亚洲视频| 亚洲精品久久久久国产| 国产一区二中文字幕在线看| 欧美性受xxxx黑人猛交| 91精品中文在线| 日韩中文字幕视频在线| 亚洲在线免费观看| 亚洲精品一区二区久| 国产美女精彩久久| 成人性生交大片免费观看嘿嘿视频| 国产日韩欧美在线观看| 欧美亚洲午夜视频在线观看| 日韩成人免费视频| 亚洲第一天堂无码专区| 国产日韩在线播放| 国产精品无码专区在线观看| 日韩福利伦理影院免费| 亚洲国产天堂网精品网站| 精品久久久免费| 久久久伊人欧美| 成人福利网站在线观看| 欧美日韩中文字幕综合视频| 2019国产精品自在线拍国产不卡| 欧美专区福利在线| 亚洲精品一区在线观看香蕉| 欧美精品在线观看91| 精品亚洲va在线va天堂资源站| 欧美疯狂xxxx大交乱88av| 九九久久久久99精品| 91高清视频在线免费观看|