js 排列 組合 的一個簡單例子


最近工作項目需要用到js排列組合,於是就寫了一個簡單的demo。 前幾天在網上找到一個寫全排列A(n,n)的code感覺還可以,於是貼出來了,

排列的實現方式: 全排列主要用到的是遞歸和數組的插入 比如12的全排列,首先把1拿出來放到elementCur,再獲取由1組成的數組[2],然后在循環把1插入到0,1的位置后再返回1,2][2,1] 如果是123那么首先獲取23的全排列[2,3][3,2],然后在插入1,[1,2,3][2,1,3][2,3,1][1,3,2][3,1,2][3,2,1] 

  /*
        全排列主要用到的是遞歸和數組的插入
        比如12的全排列,首先把1拿出來放到elementCur,再獲取由1組成的數組[2],然后在循環把1插入到0,1的位置后再返回1,2][2,1]
        如果是123那么首先獲取23的全排列[2,3][3,2],然后在插入1,[1,2,3][2,1,3][2,3,1][1,3,2][3,1,2][3,2,1]
        */
        function permutate(array/*需要進行全排列的一維數組*/, permutatedArray/*存放返回結果*/) {
            if (!permutatedArray) {
                permutatedArray = [];
            }
            if (array.length > 1) {
                //彈出第一個數
                var elementCur = array.shift();
                //排列剩余的數組
                permutate(array, permutatedArray);
                //返回剩余的數組的排列長度
                var permutatedArrayLen = permutatedArray.length;
                //第一個數與其他剩余數組所有數組組合
                for (var j = 0; j < permutatedArrayLen; j++) {
                    //彈出不齊的組
                    var p = permutatedArray.shift();
                    //把當前元素放到排列好的數組的所有位置
                    for (var i = 0; i <= p.length; i++) {
                        //復制排列好的數組
                        var r = p.slice(0);
                        //插入數據到數組的位置
                        r.splice(i, 0, elementCur);
                        //保存
                        permutatedArray.push(r)
                    }
                }
                //退出條件
            } else {
                permutatedArray.push([array[0]]);
            }
            return permutatedArray;
        }

那么我們需要一個組合C(m,n)的API,code如下,組合實現的原理非常簡單,就是依次循環數組的元素,循環的嵌套層數是有m來決定的,內部的循環下標在外部的下標加1。所以用function來組裝

  /*
        組合實現的原理非常簡單,就是依次循環數組的元素,循環的嵌套層數是有m來決定的,內部的循環下標在外部的下標加1。所以用function來組裝
        */
        function combination(arr/*n需要組合的一維數組*/, num/*m需要取幾個元素來組合*/, fun/*對組合后的元素的處理函數,如全排列permutate*/) {
            /*這里假設num最大值為10 一般A(n,m)中的m應該不會太大 */
            if (arr.length < num || num > 10)
            {
                return [];
            }
            var variable = ["a", "b", "c", "d", "e", "f", "g", "h", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u"];
            var replaceStr = "#$#";
            var str = " var arr=arguments[0]; var fun=arguments[1];  var ret=[]; for (var a = 0; a < arr.length; a++) { "+replaceStr+" } return ret;"
            for (var i = 1; i < num; i++) {
                str = str.replace(replaceStr, " for (var " + variable[i] + " =" + variable[i - 1] + "+ 1; " + variable[i] + " < arr.length; " + variable[i] + "++) { " + replaceStr + "  }")
            }
            var temp = " var temp= []; ";
            for (var i = 0; i < num; i++) {
                temp += "temp.push(arr[" + variable[i] + "]); ";
            }
            if (fun) {
                temp += " ret.push(fun(temp)); ";
            }
            else {
                temp += " ret.push(temp); ";
            }
            str = str.replace(replaceStr, temp);
            //console.log(str);
            return (new Function(str)).apply(null, [arr, fun]);
        }

那么我們一個普通的排列A(n,m)就很簡單了。調用方式如下:

 var a = combination([1, 2, 3, 4, 5, 6], 3, permutate);
        for (var i = 0; i < a.length; i++) {
            for (var j = 0; j < a[i].length; j++) {
                console.log(a[i][j].join(''));
            }
        }

 其實排列組合網上還有很多很好的精辟實現,比如以下code,個人已經加入了簡單的原理描述:

  /*
        組合主要用到了循環加遞歸的方式 實現的,個人覺得很是精辟,
        舉例來說吧choose([1,2,3,4,5,6], 3)
        第一次循環的時候 arr是[1,2,3,4,5,6],size=3,result=[],
        經過一次遞歸后的結果是什么樣的了?遞歸里面也有循環遞歸
        經過第一次循環第一次遞歸變為arr=[3,4,5,6],size=1,result=[1,2],所以結果就出來了[1,2,3][1,2,4][1,2,5][1,2,6]
        那么第一次循環第二次遞歸arr=[4,5,6],size=1,result=[1,3],所以結果就出來了[1,3,4][1,3,5][1,3,6]
        那么第一次循環第三次遞歸arr=[5,6],size=1,result=[1,4],所以結果就出來了[1,4,5][1,4,6]
        那么第一次循環第四次遞歸arr=[6],size=1,result=[1,5],所以結果就出來了[1,5,6]
        那么第二次循環第一次遞歸變為arr=[4,5,6],size=1,result=[2,3],所以結果就出來了[2,3,4][2,3,5][2,3,6]
        */
        function choose(arr, size) {
            var allResult = [];
            (function (arr, size, result) {
                var arrLen = arr.length;
                if (size > arrLen) {
                    return;
                }
                if (size == arrLen) {
                    allResult.push([].concat(result, arr))
                } else {
                    for (var i = 0 ; i < arrLen; i++) {
                        var newResult = [].concat(result);
                        newResult.push(arr[i]);

                        if (size == 1) {
                            allResult.push(newResult);
                        } else {
                            var newArr = [].concat(arr);
                            newArr.splice(0, i + 1);
                            arguments.callee(newArr, size - 1, newResult);
                        }
                    }
                }
            })(arr, size, []);
            return allResult;
        }
        /*
    這里的排列和組合一樣 也是運用循環和遞歸的思想,比如arr=[1,2,3] ,size=3
    第一次循環curItem=1 第一次遞歸newArr=3,result=[1,2] 所以結果是[1,2,3]
    第一次循環curItem=1 第二次遞歸newArr=2,result=[1,3] 所以結果是[1,3,2]
    第二次循環curItem=2 第一次遞歸newArr=3,result=[2,1] 所以結果是[2,1,3]
    第二次循環curItem=2 第二次遞歸newArr=1,result=[2,3] 所以結果是[2,3,1]
    */
        function queue(arr, size) {
            if (size > arr.length) { return; }
            var allResult = [];

            (function (arr, size, result) {
                if (result.length == size) {
                    allResult.push(result);
                } else {
                    for (var i = 0, len = arr.length; i < len; i++) {
                        var newArr = [].concat(arr),
                            curItem = newArr.splice(i, 1);
                        arguments.callee(newArr, size, [].concat(result, curItem));
                    }
                }
            })(arr, size, []);

            return allResult;
        }
        function showResult(result) {
            console.log('The number of result sets: ' + result.length);
            for (var i = 0, len = result.length; i < len; i++) {
                console.log(result[i]);
            }
        }

        // showResult(choose([1, 2, 3, 4, 5, 6], 3));
        showResult(queue([1, 2, 3], 3));

有不當的地方還請大家指正!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM