ในการอธิบายการเรียงสับเปลี่ยนขององค์ประกอบ n คุณจะเห็นว่าสำหรับตำแหน่งที่องค์ประกอบแรกลงเอยที่คุณมีความเป็นไปได้ n ดังนั้นคุณจึงสามารถอธิบายสิ่งนี้ด้วยตัวเลขระหว่าง 0 ถึง n-1 สำหรับตำแหน่งที่องค์ประกอบถัดไปไปสิ้นสุดที่คุณมีความเป็นไปได้ที่เหลืออยู่ n-1 ดังนั้นคุณสามารถอธิบายสิ่งนี้ด้วยตัวเลขระหว่าง 0 ถึง n-2
และอื่น ๆ จนกว่าคุณจะมี n ตัวเลข
เป็นตัวอย่างสำหรับ n = 5 พิจารณาการเปลี่ยนแปลงที่นำไปabcde
caebd
a
องค์ประกอบแรกจบลงในตำแหน่งที่สองดังนั้นเราจึงกำหนดดัชนี1
b
ปลายขึ้นที่ตำแหน่งที่สี่ซึ่งจะเป็นดัชนีที่ 3 แต่ก็เป็นที่สามที่เหลือหนึ่งดังนั้นเราจึงกำหนด2
c
ปลายขึ้นที่ตำแหน่งแรกที่เหลือซึ่งเป็นเสมอ0
d
จบลงที่ตำแหน่งสุดท้ายที่เหลืออยู่ซึ่ง (out of เหลืออยู่เพียงสองตำแหน่ง) เป็น1
e
จบลงที่ตำแหน่งเดียวที่เหลืออยู่, การจัดทำดัชนีที่0
ดังนั้นเราจึงมีลำดับดัชนี{1, 2, 0, 1, 0}
ตอนนี้คุณรู้แล้วว่าตัวอย่างเช่นในเลขฐานสอง 'xyz' หมายถึง z + 2y + 4x สำหรับเลขฐานสิบ
คือ z + 10y + 100x ตัวเลขแต่ละตัวจะถูกคูณด้วยน้ำหนักบางส่วนและผลลัพธ์จะถูกสรุป รูปแบบที่ชัดเจนของน้ำหนักแน่นอนว่าน้ำหนักคือ w = b ^ k โดย b เป็นฐานของตัวเลขและ k ดัชนีของตัวเลข (ฉันจะนับหลักจากทางขวาเสมอและเริ่มต้นที่ดัชนี 0 สำหรับตัวเลขทางขวาสุดในทำนองเดียวกันเมื่อฉันพูดถึงหลัก 'แรก' ฉันหมายถึงขวาสุด)
เหตุผลว่าทำไมน้ำหนักสำหรับตัวเลขตามรูปแบบนี้คือการที่มีจำนวนมากที่สุดที่สามารถแทนด้วยตัวเลขจาก 0 ถึง k จะต้องตรง 1 ต่ำกว่าจำนวนต่ำสุดที่สามารถแสดงโดยเฉพาะการใช้หลัก k + 1 ในไบนารี 0111 ต้องต่ำกว่า 1,000 หนึ่งในทศนิยม 099999 ต้องต่ำกว่า 100000 หนึ่งรายการ
การเข้ารหัสเป็นตัวแปรฐาน
ระยะห่างระหว่างตัวเลขที่ตามมาคือ 1 เป็นกฎที่สำคัญ ตระหนักถึงนี้เราสามารถแสดงลำดับของดัชนีของเราโดยจำนวนตัวแปรฐาน ฐานของแต่ละหลักคือจำนวนของความเป็นไปได้ที่แตกต่างกันสำหรับตัวเลขนั้น สำหรับทศนิยมแต่ละหลักมีความเป็นไปได้ 10 สำหรับระบบของเราตัวเลขที่อยู่ขวาสุดจะมี 1 ความเป็นไปได้และทางซ้ายสุดจะมีความเป็นไปได้ n แต่เนื่องจากตัวเลขทางขวาสุด (ตัวเลขสุดท้ายในลำดับของเรา) เป็น 0 เสมอเราจึงปล่อยมันออกไป นั่นหมายความว่าเราเหลือฐาน 2 ถึง n โดยทั่วไปหลัก k จะมีฐาน 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] ควรเป็น 1 เสมอเริ่มจากตรงนั้นเรามีค่าต่อไปนี้:
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 นี่คือ [k] คือองค์ประกอบ k'th (ขวาสุดเริ่มต้นที่ 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
}
สิ่งนี้จะถอดรหัส 37 ของเรากลับไปเป็น {1, 2, 0, 1} sequence
ได้อย่างถูกต้อง( จะอยู่{1, 0, 2, 1}
ในตัวอย่างโค้ดนี้ แต่อะไรก็ตาม ... ตราบใดที่คุณทำดัชนีอย่างเหมาะสม) เราเพียงแค่ต้องเพิ่ม 0 ที่ด้านขวาสุด (โปรดจำไว้ว่าองค์ประกอบสุดท้ายจะมีความเป็นไปได้เพียงอย่างเดียวสำหรับตำแหน่งใหม่) เพื่อเรียกลำดับเดิมของเรากลับมา {1, 2, 0, 1, 0}
การอนุญาตรายการโดยใช้ลำดับดัชนี
คุณสามารถใช้อัลกอริทึมด้านล่างเพื่ออนุญาตรายการตามลำดับดัชนีเฉพาะ มันเป็นอัลกอริทึม O (n²) แต่น่าเสียดาย
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
to caebd
จะแสดงโดย {1, 3, 0, 4, 2} แต่ละดัชนีตั้งแต่ 0 ถึง 4 (หรือโดยทั่วไป 0 ถึง n-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²) หากคุณต้องการใช้การเรียงสับเปลี่ยนหลาย ๆ ครั้งก่อนอื่นให้แปลงเป็นการแสดงทั่วไป