1. 程式人生 > >每日一小練——按字典順序列出全部排列

每日一小練——按字典順序列出全部排列

break 研究 mes har 實驗 tom 規律 pop 廚房

上得廳堂,下得廚房,寫得代碼,翻得圍墻。歡迎來到睿不可擋的每日一小練!


題目:按字典順序列出全部排列


內容:請寫一個程序,用字典順序列出n個元素的全部排列


這個問題有點小復雜,不是太好想。反正我是想了好久

看到這個題目我先是想到的就是遞歸由於這個題目就是用指針對高位選擇,然後將指針傳給臨近的低位再選擇

只是細致研究原來沒這麽簡單

以n=4舉例當處理以1開頭的排列時1234到1432,可是在排列2開頭的時候不太好建立統一的遞歸關系。

(沒辦法太統一的遞歸方法中將後面的數字選出來),所以將第一位分類數字經行單獨處理,事實上第一位數字的選擇也是又規律

可循的。

1234 1432

2134 2431

3124 3421

4123 4321

12345 15432

21345 25431

....

能夠看出1和2換時2都在最後一位,2和3換時,3在倒數第二位。。

就是你換第i個數時,就在倒數第i-1位。

然後我們再來處理除第一位的排列即從i,1,2,3,4,..i-1,i+i,..n(如果第一位是i)到i,n,...i+1,i-1,...3,2,1。

的排列

事實上這裏也是有規律的。就是先從後向前查找第一個順序相鄰的位置然後交換,然後對交換後面的排列逆序

(事實上這就是分解了我們人類排序的步驟,僅僅是人的智能比較快。我們感受不到)。

比方 21354 從後向前第一個順序相鄰是35交換53為21534然後對後面逆序21435就是21354的後面一個數了。

當數列中沒有順序相鄰了。我們的排列就結束了

如 4321,54321。

所以我們就能夠依照這個規律來編敲代碼了。


#include <iostream>
using namespace std;

int set[1000];
bool signal = false;
int n;

int _tmain(int argc, _TCHAR* argv[])
{
	void changeFirst();
	cout << "請輸入排列的集合的最大整數n:" << endl;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		set[i] = i + 1;
	}
	cout << "該集合的全部排列為:" << endl;
	changeFirst();
	getchar();
	getchar();
	return 0;
}

void swap(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}

void reverse(int index_Start, int index_End)
{
	int length = index_End - index_Start;
	for (int i = 0; i <= length / 2; i++)
		swap(set[i + index_Start], set[length - i + index_Start]);

}

void permutationSet()
{
	for (int x = 0; x < n; x++)
		cout << set[x] << "  ";
	cout << endl;
	signal = false;
	int i, j, k;
	for (i = n - 2; i>0; i--)
	if (set[i]<set[i + 1])
	{
		j = i + 1;
		signal = true;
		break;
	}
	if (signal == false)
		return;
	for (k = n - 1; k>0; k--)
	if (set[k]>set[i])
		break;
	swap(set[i], set[k]);
	reverse(j, n - 1);
	permutationSet();
}

void changeFirst()
{
	int i = n - 1;
	while (i >= 0)
	{
		permutationSet();
		swap(set[0], set[i]);
		reverse(1, n - 1);
		i--;
	}
}

實驗結果


技術分享


歡迎大家增加每日一小練。嘿嘿!

每天練一練,日久見功夫,加油。


-End-

參考文獻:《c語言名題精選百則》




每日一小練——按字典順序列出全部排列