N तत्वों के क्रमचय का वर्णन करने के लिए, आप देखते हैं कि जिस स्थिति के लिए पहला तत्व समाप्त होता है, उसके लिए आपके पास n संभावनाएँ हैं, इसलिए आप इसे 0 और n-1 के बीच की संख्या के साथ वर्णित कर सकते हैं। अगले तत्व के समाप्त होने की स्थिति के लिए, आपके पास n-1 शेष संभावनाएं हैं, इसलिए आप इसे 0 और n-2 के बीच की संख्या के साथ वर्णित कर सकते हैं।
Et cera जब तक आपके पास n नंबर नहीं है।
N = 5 के लिए एक उदाहरण के रूप में, उस क्रमांकन पर विचार करें जो लाता abcde
है caebd
।
a
, पहला तत्व, दूसरे स्थान पर समाप्त होता है, इसलिए हम इसे 1 इंडेक्स प्रदान करते हैं ।
b
चौथे स्थान पर समाप्त होता है, जो कि सूचकांक 3 होगा, लेकिन यह तीसरा शेष है, इसलिए हम इसे 2 असाइन करते हैं ।
c
पहले शेष स्थान पर समाप्त होता है, जो हमेशा 0 होता है ।
d
अंतिम शेष स्थिति पर समाप्त होता है, जो (केवल दो शेष पदों में से) 1 है ।
e
केवल शेष स्थिति में समाप्त होता है, 0 पर अनुक्रमित ।
इसलिए हमारे पास अनुक्रम अनुक्रम {1, 2, 0, 1, 0} है ।
अब आप जानते हैं कि उदाहरण के लिए एक द्विआधारी संख्या में, 'xyz' का अर्थ है z + 2y + 4x। दशमलव संख्या के लिए,
यह z + 10y + 100x है। प्रत्येक अंक को कुछ वजन से गुणा किया जाता है, और परिणाम को अभिव्यक्त किया जाता है। वजन में स्पष्ट पैटर्न निश्चित रूप से है कि वजन w = b ^ k है, संख्या का आधार और अंक के सूचकांक के साथ बी। (मैं हमेशा दाईं ओर से अंकों की गणना करूंगा और सबसे सही अंक के लिए सूचकांक 0 से शुरू करूंगा। इसी तरह जब मैं 'पहले' अंक के बारे में बात करता हूं तो मेरा मतलब सबसे सही है।)
अंकों के लिए वज़न इस पैटर्न का अनुसरण करने का कारण यह है कि उच्चतम अंक जिसे 0 से k तक के अंकों द्वारा दर्शाया जा सकता है, वह उस न्यूनतम संख्या से लगभग 1 कम होना चाहिए जिसे केवल अंक k + 1 का उपयोग करके दर्शाया जा सकता है। बाइनरी में, 0111 1000 से एक कम होना चाहिए। दशमलव में, 099999 100000 से कम होना चाहिए।
चर-आधार
को एन्कोड करना बाद की संख्याओं के बीच की दूरी को ठीक 1 होना महत्वपूर्ण नियम है। इसे महसूस करते हुए, हम एक चर-आधार संख्या द्वारा अपने सूचकांक अनुक्रम का प्रतिनिधित्व कर सकते हैं । प्रत्येक अंक का आधार उस अंक के लिए विभिन्न संभावनाओं की राशि है। दशमलव के लिए प्रत्येक अंक में 10 संभावनाएँ होती हैं, हमारे सिस्टम के लिए सबसे सही अंक में 1 संभावना होती है और सबसे बाईं ओर n संभावनाएँ होती हैं। लेकिन चूंकि सबसे सही अंक (हमारे अनुक्रम में अंतिम संख्या) हमेशा 0 होती है, हम इसे छोड़ देते हैं। इसका मतलब है कि हम 2 से n के आधार पर बचे हैं। सामान्य तौर पर, k'th अंक में आधार b [k] = k + 2 होगा। अंक k के लिए अनुमत उच्चतम मूल्य h [k] = b [k] - 1 = k + 1 है।
अंकों के भार w [k] के बारे में हमारे नियम के लिए आवश्यक है कि h [i] * w [i] का योग, जहाँ मैं i = 0 से i = k तक जाता हूँ, 1 * w [k + 1] के बराबर है। बार-बार कहा गया, w [k + 1] = w [k] + h [k] * w [k] = w [k] * (h [k] + 1)। पहला वजन w [0] हमेशा १ होना चाहिए। वहाँ से शुरू होकर, हमारे पास निम्नलिखित मूल्य हैं:
k h[k] w[k]
0 1 1
1 2 2
2 3 6
3 4 24
... ... ...
n-1 n n!
(सामान्य संबंध w [k-1] = k! प्रेरण द्वारा आसानी से साबित हो जाता है।)
हमारे अनुक्रम को परिवर्तित करने से हमें जो संख्या मिलेगी, उसके बाद s [k] * w [k] का योग होगा, k से 0 से n-1 तक चलने वाला। यहाँ s [k] क्रम का तत्व है (सबसे सही, 0 पर शुरू)। एक उदाहरण के रूप में, हमारे {1, 2, 0, 1, 0} को लें, जिसमें पहले बताए गए सही तत्व को छीन लिया जाए: {1, 2, 0, 1} । हमारा योग 1 * 1 + 0 * 2 + 2 * 6 + 1 * 24 = 37 है ।
ध्यान दें कि यदि हम प्रत्येक सूचकांक के लिए अधिकतम स्थान लेते हैं, तो हमारे पास {4, 3, 2, 1, 0} होगा, और यह 119 में परिवर्तित हो जाएगा। चूंकि हमारी संख्या एन्कोडिंग में भार को चुना गया था ताकि हम छोड़ें नहीं कोई भी संख्या, सभी संख्याएँ 0 से 119 तक मान्य हैं। इनमें से ठीक 120 हैं, जो n है! हमारे उदाहरण में n = 5 के लिए, विभिन्न क्रमपरिवर्तन की संख्या ठीक है। तो आप देख सकते हैं कि हमारे एन्कोडेड नंबर पूरी तरह से सभी संभावित क्रमांकन निर्दिष्ट करते हैं।
वैरिएबल-बेस से
डिकोडिंग बाइनरी या दशमलव में कनवर्ट करने के समान है। सामान्य एल्गोरिथ्म यह है:
int number = 42;
int base = 2;
int[] bits = new int[n];
for (int k = 0; k < bits.Length; k++)
{
bits[k] = number % base;
number = number / base;
}
हमारे चर-आधार संख्या के लिए:
int n = 5;
int number = 37;
int[] sequence = new int[n - 1];
int base = 2;
for (int k = 0; k < sequence.Length; k++)
{
sequence[k] = number % base;
number = number / base;
base++; // b[k+1] = b[k] + 1
}
यह सही ढंग से करने के लिए {1, 2, 0, 1} हमारे 37 वापस डीकोड ( sequence
होगा {1, 0, 2, 1}
इस कोड उदाहरण में है, लेकिन जो कुछ भी ... जब तक आप सूचकांक के रूप में उचित रूप से)। हमें अपने मूल अनुक्रम {1, 2, 0, 1, 0} को वापस पाने के लिए हमें सही छोर पर 0 जोड़ना होगा (अंतिम तत्व हमेशा अपनी नई स्थिति के लिए केवल एक ही संभावना है) याद रखें।
सूचकांक अनुक्रम का उपयोग करके एक सूची की अनुमति देना
आप एक विशिष्ट सूचकांक अनुक्रम के अनुसार सूची की अनुमति देने के लिए नीचे दिए गए एल्गोरिदम का उपयोग कर सकते हैं। यह दुर्भाग्य से एक O (n an) एल्गोरिथ्म है।
int n = 5;
int[] sequence = new int[] { 1, 2, 0, 1, 0 };
char[] list = new char[] { 'a', 'b', 'c', 'd', 'e' };
char[] permuted = new char[n];
bool[] set = new bool[n];
for (int i = 0; i < n; i++)
{
int s = sequence[i];
int remainingPosition = 0;
int index;
// Find the s'th position in the permuted list that has not been set yet.
for (index = 0; index < n; index++)
{
if (!set[index])
{
if (remainingPosition == s)
break;
remainingPosition++;
}
}
permuted[index] = list[i];
set[index] = true;
}
क्रमपरिवर्तन का सामान्य प्रतिनिधित्व आम
तौर पर आप अनपेक्षित रूप से एक क्रमचय का प्रतिनिधित्व नहीं करते हैं जैसा कि हमने किया है, लेकिन बस क्रमचय लागू होने के बाद प्रत्येक तत्व की पूर्ण स्थिति से। हमारे उदाहरण {1, 2, 0, 1, 0} के abcde
लिए caebd
आमतौर पर {1, 3, 0, 4, 2} द्वारा दर्शाया जाता है। प्रत्येक सूचकांक 0 से 4 (या सामान्य रूप से, 0 से एन -1) इस प्रतिनिधित्व में एक बार होता है।
इस रूप में क्रमपरिवर्तन लागू करना आसान है:
int[] permutation = new int[] { 1, 3, 0, 4, 2 };
char[] list = new char[] { 'a', 'b', 'c', 'd', 'e' };
char[] permuted = new char[n];
for (int i = 0; i < n; i++)
{
permuted[permutation[i]] = list[i];
}
यह बहुत समान है:
for (int i = 0; i < n; i++)
{
list[i] = permuted[permutation[i]];
}
हमारे प्रतिनिधित्व से सामान्य प्रतिनिधित्व पर
ध्यान दें कि यदि हम अपने अनुक्रम अनुक्रम का उपयोग करके किसी सूची को अनुमति देने के लिए हमारे एल्गोरिथ्म को लेते हैं, और इसे पहचान क्रमचय {0, 1, 2, ..., n-1} पर लागू करते हैं, तो हम प्राप्त करते हैं उलटा क्रमचय, सामान्य रूप में प्रतिनिधित्व किया। ( {2, 0, 4, 1, 3} हमारे उदाहरण में)।
गैर-औंधा अवतरण प्राप्त करने के लिए, हम क्रमांकन एल्गोरिथ्म लागू करते हैं जो मैंने अभी दिखाया:
int[] identity = new int[] { 0, 1, 2, 3, 4 };
int[] inverted = { 2, 0, 4, 1, 3 };
int[] normal = new int[n];
for (int i = 0; i < n; i++)
{
normal[identity[i]] = list[i];
}
या आप उलटा क्रमपरिवर्तन एल्गोरिथ्म का उपयोग करके बस सीधे क्रमपरिवर्तन लागू कर सकते हैं:
char[] list = new char[] { 'a', 'b', 'c', 'd', 'e' };
char[] permuted = new char[n];
int[] inverted = { 2, 0, 4, 1, 3 };
for (int i = 0; i < n; i++)
{
permuted[i] = list[inverted[i]];
}
ध्यान दें कि सामान्य रूप में क्रमपरिवर्तन से निपटने के लिए सभी एल्गोरिदम O (n) हैं, जबकि हमारे रूप में क्रमपरिवर्तन लागू करने के लिए O (n²) है। यदि आपको कई बार क्रमपरिवर्तन लागू करने की आवश्यकता है, तो पहले इसे सामान्य प्रतिनिधित्व में परिवर्तित करें।