Microsoft MVP성태의 닷넷 이야기
.NET Framework: 581. C# - 순열(Permutation) 예제 코드 [링크 복사], [링크+제목 복사],
조회: 29478
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

C# - 순열(Permutation) 예제 코드

조합이 나오면,

C# - 조합(Combination) 예제 코드
; https://www.sysnet.pe.kr/2/0/10954

빠지지 않는 것이 바로 순열입니다. 위의 조합 코드를 만든 James McCaffrey가 순열도 만들어 놓았기 때문에 그대로 사용해도 좋습니다. ^^

Using Permutations in .NET for Improved Systems Security
; http://delphi.ktop.com.tw/download/upload/41338_Using%20Permutations%20in%20.NET%20for%20Improved%20Systems%20Security.doc

namespace ConsoleApplication1
{
    class Permutation
    {
        private int[] data = null;
        private int order = 0;

        public Permutation(int n)
        {
            this.data = new int[n];
            for (int i = 0; i < n; ++i)
            {
                this.data[i] = i;
            }

            this.order = n;
        }

        public Permutation Successor()
        {
            if (this.order <= 1)
            {
                return null;
            }

            Permutation result = new Permutation(this.order);

            int left, right;
            for (int k = 0; k < result.order; ++k)  // Step #0 - copy current data into result
            {
                result.data[k] = this.data[k];
            }

            left = result.order - 2;  // Step #1 - Find left value 
            while ((result.data[left] > result.data[left + 1]) && (left >= 1))
            {
                --left;
            }

            if ((left == 0) && (this.data[left] > this.data[left + 1]))
            {
                return null;
            }

            right = result.order - 1;  // Step #2 - find right; first value > left
            while (result.data[left] > result.data[right])
            {
                --right;
            }

            int temp = result.data[left];  // Step #3 - swap [left] and [right]
            result.data[left] = result.data[right];
            result.data[right] = temp;


            int i = left + 1;              // Step #4 - order the tail
            int j = result.order - 1;

            while (i < j)
            {
                temp = result.data[i];
                result.data[i++] = result.data[j];
                result.data[j--] = temp;
            }

            return result;
        }

        internal static long Choose(int length)
        {
            long answer = 1;

            for (int i = 1; i <= length; i ++)
            {
                checked { answer = answer * i; }
            }

            return answer;
        }

        public string[] ApplyTo(string[] arr)
        {
            if (arr.Length != this.order)
            {
                return null;
            }

            string[] result = new string[arr.Length];
            for (int i = 0; i < result.Length; ++i)
            {
                result[i] = arr[this.data[i]];
            }

            return result;
        }

        public override string ToString()
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();

            sb.Append("( ");
            for (int i = 0; i < this.order; ++i)
            {
                sb.Append(this.data[i].ToString() + " ");
            }
            sb.Append(")");

            return sb.ToString();
        }

    }
}

같은 사람이 만들었기 때문에 사용법도 순열과 매우 흡사하게 구성됩니다.

string[] items = new string[] { "apple", "banana", "cherry" };

Permutation c = new Permutation(items.Length);

string[] snapshot = null;

while (c != null)
{
    snapshot = c.ApplyTo(items);
    DisplayItems(snapshot);

    c = c.Successor();
}

/*
출력 결과:

{ apple, banana, cherry }
{ apple, cherry, banana }
{ banana, apple, cherry }
{ banana, cherry, apple }
{ cherry, apple, banana }
{ cherry, banana, apple }
*/

또한, 제네릭과 IEnumerable 메서드를 추가 적용해 보면,

public class Permutation<TData> : IEnumerable<TData[]>
{
    private int[] data = null;
    private int order = 0;
    private TData[] elems;

    public Permutation(TData[] items)
    {
        this.order = items.Length;
        this.data = new int[this.order];
        this.elems = items;
        for (int i = 0; i < this.order; ++i)
        {
            this.data[i] = i;
        }
    }

    public Permutation<TData> Successor()
    {
        if (this.order <= 1)
        {
            return null;
        }

        Permutation<TData> result = new Permutation<TData>(this.elems);

        int left, right;
        for (int k = 0; k < result.order; ++k)  // Step #0 - copy current data into result
        {
            result.data[k] = this.data[k];
        }

        left = result.order - 2;  // Step #1 - Find left value 
        while ((result.data[left] > result.data[left + 1]) && (left >= 1))
        {
            --left;
        }

        if ((left == 0) && (this.data[left] > this.data[left + 1]))
        {
            return null;
        }

        right = result.order - 1;  // Step #2 - find right; first value > left
        while (result.data[left] > result.data[right])
        {
            --right;
        }

        int temp = result.data[left];  // Step #3 - swap [left] and [right]
        result.data[left] = result.data[right];
        result.data[right] = temp;

        int i = left + 1;              // Step #4 - order the tail
        int j = result.order - 1;

        while (i < j)
        {
            temp = result.data[i];
            result.data[i++] = result.data[j];
            result.data[j--] = temp;
        }

        return result;
    }

    internal static long Choose(int length)
    {
        long answer = 1;

        for (int i = 1; i <= length; i++)
        {
            checked { answer = answer * i; }
        }

        return answer;
    }

    public TData[] ApplyTo(TData[] arr)
    {
        if (arr.Length != this.order)
        {
            return null;
        }

        TData[] result = new TData[arr.Length];
        for (int i = 0; i < result.Length; ++i)
        {
            result[i] = arr[this.data[i]];
        }

        return result;
    }

    public override string ToString()
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();

        sb.Append("( ");
        for (int i = 0; i < this.order; ++i)
        {
            sb.Append(this.data[i].ToString() + " ");
        }
        sb.Append(")");

        return sb.ToString();
    }

    public IEnumerator<TData[]> GetEnumerator()
    {
        Permutation<TData> p = new Permutation<TData>(this.elems);
        TData[] snapshot = null;

        while (p != null)
        {
            snapshot = p.ApplyTo(this.elems);
            yield return snapshot;

            p = p.Successor();
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        Permutation<TData> p = new Permutation<TData>(this.elems);
        TData[] snapshot = null;

        while (p != null)
        {
            snapshot = p.ApplyTo(this.elems);
            yield return snapshot;

            p = p.Successor();
        }
    }
}

배열의 요소 타입에 상관없이 사용할 수 있습니다.

{
    string[] items = new string[] { "apple", "banana", "cherry" };
    Permutation<string> p = new Permutation<string>(items);

    foreach (var result in p)
    {
        PrintElems(result);
    }
}

{
    int[] items = new int[] { 1, 2, 3 };
    Permutation<int> p = new Permutation<int>(items);

    foreach (var result in p)
    {
        PrintElems(result);
    }
}

private static void PrintElems(T[] elems)
{
    Console.Write("{ ");

    foreach (var elem in elems)
    {
        Console.Write(elem + ", ");
    }

    Console.WriteLine("}");
}

/* 출력 결과
{ apple, banana, cherry, }
{ apple, cherry, banana, }
{ banana, apple, cherry, }
{ banana, cherry, apple, }
{ cherry, apple, banana, }
{ cherry, banana, apple, }
{ 1, 2, 3, }
{ 1, 3, 2, }
{ 2, 1, 3, }
{ 2, 3, 1, }
{ 3, 1, 2, }
{ 3, 2, 1, }
*/

첨부한 파일은, "Using Permutations in .NET for Improved Systems Security" 워드 파일과 이 글의 예제 코드입니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 11/12/2022]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 31  32  33  34  35  36  37  38  39  40  41  42  [43]  44  45  ...
NoWriterDateCnt.TitleFile(s)
1820정성태11/23/201420653.NET Framework: 485. Mono Profiler에서 IL 코드 변경이 가능할까? - 두 번째 이야기파일 다운로드1
1816정성태11/20/201420871.NET Framework: 484. Mono Profiler에서 IL 코드 변경이 가능할까?
1815정성태11/18/201418875.NET Framework: 483. 코드로 살펴 보는 ETW의 활성화 시점 [2]
1812정성태11/17/201419697.NET Framework: 482. ETW 자동 생성 코드의 VerificationException 예외 발생
1811정성태11/16/201421019.NET Framework: 481. Mono 내부의 문자열 처리 방식은 UTF-8
1810정성태11/15/201457727.NET Framework: 480. C# - 배치 파일 실행하고 출력 결과를 얻는 방법 [4]
1809정성태11/11/201422910.NET Framework: 479. Mono Profiler를 Unity의 Plugin으로 사용하는 방법
1808정성태11/11/201423231.NET Framework: 478. C# - 폴더 경로 문자열에서 "..", "." 표기를 고려한 최종 문자열을 얻는 방법 [2]
1806정성태11/10/201425172.NET Framework: 477. SeCreateGlobalPrivilege 특권과 WCF NamedPipe
1805정성태11/5/201422028.NET Framework: 476. Visual Studio에서 Mono용 Profiler 개발 [3]파일 다운로드1
1804정성태11/5/201428283.NET Framework: 475. ETW(Event Tracing for Windows)를 C#에서 사용하는 방법 [9]파일 다운로드1
1793정성태10/27/201423179.NET Framework: 474. C# - chromiumembedded 사용 - 두 번째 이야기 [2]파일 다운로드1
1792정성태10/27/201423309.NET Framework: 473. WebClient 객체에 쿠키(Cookie)를 사용하는 방법
1784정성태10/22/201430037.NET Framework: 472. C/C++과 C# 사이의 메모리 할당/해제 방법파일 다운로드1
1773정성태10/8/201429863.NET Framework: 471. 웹 브라우저로 다운로드가 되는 파일을 왜 C# 코드로 하면 안되는 걸까요? [1]
1772정성태10/3/201418641.NET Framework: 470. C# 3.0의 기본 인자(default parameter)가 .NET 1.1/2.0에서도 실행될까? [3]
1765정성태9/30/201426137.NET Framework: 469. Unity3d에서 transform을 변수에 할당해 사용하는 특별한 이유가 있을까요?
1763정성태9/30/201423922.NET Framework: 468. PDB 파일을 연동해 소스 코드 라인 정보를 알아내는 방법파일 다운로드1
1762정성태9/30/201424698.NET Framework: 467. 닷넷에서 EIP/RIP 레지스터 값을 구하는 방법 [1]파일 다운로드1
1761정성태9/29/201421732.NET Framework: 466. 윈도우 운영체제의 보안 그룹 이름 및 설명 문자열을 바꾸는 방법파일 다운로드1
1760정성태9/28/201419948.NET Framework: 465. ICorProfilerInfo::GetILToNativeMapping 메서드가 0x80131358을 반환하는 경우
1751정성태9/20/201438988.NET Framework: 464. 프로세스 간 통신 시 소켓 필요 없이 간단하게 Pipe를 열어 통신하는 방법 [1]파일 다운로드1
1750정성태9/20/201423877.NET Framework: 463. PInvoke 호출을 이용한 비동기 파일 작업파일 다운로드1
1749정성태9/20/201423792.NET Framework: 462. 커널 객체를 위한 null DACL 생성 방법파일 다운로드1
1746정성태9/18/201426112.NET Framework: 461. .NET EXE 파일을 닷넷 프레임워크 버전에 상관없이 실행할 수 있을까요? - 두 번째 이야기 [6]파일 다운로드1
1744정성태9/17/201431087.NET Framework: 460. GetTickCount / GetTickCount64와 0x7FFE0000 주솟값 [4]파일 다운로드1
... 31  32  33  34  35  36  37  38  39  40  41  42  [43]  44  45  ...