實現自然數N的全排列

yangtingkun發表於2009-02-17

今天同事問了一個問題,如何實現一個數N的全排列,也就是Pn。對於一個3來說,列印結果應該包括123132213231312321

 

 

當然還有一個小要求,不能使用遞迴演算法。其實演算法應該不復雜,不是遞迴就是迴圈。想了一下,覺得不難實現。

SQL其實最擅長這種類似笛卡兒的操作,下面是用SQL實現4個數的排列P4

SQL> WITH A AS (SELECT ROWNUM ID FROM DUAL CONNECT BY LEVEL <= 4)
  2  SELECT A.ID || B.ID || C.ID || D.ID
  3  FROM A, A B, A C, A D
  4  WHERE A.ID != B.ID
  5  AND A.ID != C.ID
  6  AND A.ID != D.ID
  7  AND B.ID != C.ID
  8  AND B.ID != D.ID
  9  AND C.ID != D.ID;

A.ID||B.ID||C.ID||D.ID
---------------------------------------------------------------------
1234
1243
1324
1342
1423
1432
2134
2143
2314
2341
2413
2431
3124
3142
3214
3241
3412
3421
4123
4132
4213
4231
4312
4321

已選擇24行。

不過SQL實現固定值的排列結果和簡單,但是如果輸入引數是變數,那麼SQL就沒有辦法寫了,不過利用PL/SQLSQL的配合還是很容易實現的,程式碼如下:

SQL> CREATE OR REPLACE FUNCTION F_TEST (P_IN NUMBER) RETURN SYS_REFCURSOR AS
  2   V_STR VARCHAR2(32767);
  3   V_RETURN SYS_REFCURSOR;
  4  BEGIN
  5   V_STR := 'WITH A AS (SELECT ROWNUM ID FROM DUAL CONNECT BY LEVEL <= ' || P_IN || ') SELECT ';
  6   FOR I IN 1..P_IN LOOP
  7    V_STR := V_STR || 'A' || I || '.ID || ';
  8   END LOOP;
  9   V_STR := RTRIM(V_STR, '| ') || ' FROM ';
 10   FOR I IN 1..P_IN LOOP
 11    V_STR := V_STR || 'A A' || I || ', ';
 12   END LOOP;
 13   V_STR := RTRIM(V_STR, ', ') || ' WHERE ';
 14   FOR I IN 1..P_IN LOOP
 15    FOR J IN I+1..P_IN LOOP
 16     V_STR := V_STR || 'A' || I || '.ID != A' || J || '.ID AND ';
 17    END LOOP;
 18   END LOOP;
 19   OPEN V_RETURN FOR SUBSTR(V_STR, 1, LENGTH(V_STR) - 4);
 20   RETURN V_RETURN;
 21  END;
 22  /

函式已建立。

SQL> SELECT F_TEST(3) FROM DUAL;

F_TEST(3)
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

A1.ID||A2.ID||A3.ID
--------------------------------------------------------------------------------------------
321
231
312
132
213
123

已選擇6行。

當然,如果嚴謹一點,還應該對大於9和小於1的數進行輸入判斷,並對1進行單獨的處理,不過不到30分鐘的時間能實現到這樣已經比較滿意了。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-553611/,如需轉載,請註明出處,否則將追究法律責任。

相關文章