Fungsi pemasangan pasangan benar-benar salah satu yang lebih baik di luar sana mengingat itu sederhana, cepat dan efisien ruang, tetapi ada sesuatu yang lebih baik diterbitkan di Wolfram oleh Matthew Szudzik, di sini . Batasan fungsi pasangan Cantor (relatif) adalah bahwa kisaran hasil yang disandikan tidak selalu tetap dalam batas-batas 2N
integer bit jika inputnya adalah N
integer bit dua . Artinya, jika input saya adalah 16
bilangan bulat dua mulai dari 0 to 2^16 -1
, maka ada 2^16 * (2^16 -1)
kombinasi input yang mungkin, sehingga dengan angka bit Prinsip Pigeonhole yang , kita memerlukan output ukuran setidaknya , yang sama dengan , atau dengan kata lain, peta jelas harus layak idealnya. Ini mungkin tidak terlalu penting praktis dalam dunia pemrograman.2^16 * (2^16 -1)
2^32 - 2^16
32
Fungsi pemasangan penyanyi :
(a + b) * (a + b + 1) / 2 + a; where a, b >= 0
Pemetaan untuk dua bilangan bulat maksimal 16 bit (65535, 65535) maksimum adalah 8589803520 yang seperti yang Anda lihat tidak dapat masuk ke dalam 32 bit.
Masukkan fungsi Szudzik :
a >= b ? a * a + a + b : a + b * b; where a, b >= 0
Pemetaan untuk (65535, 65535) sekarang akan menjadi 4294967295 yang seperti yang Anda lihat adalah bilangan bulat 32 bit (0 hingga 2 ^ 32 -1). Di sinilah solusi ini ideal, hanya memanfaatkan setiap titik di ruang itu, jadi tidak ada yang bisa mendapatkan ruang lebih efisien.
Sekarang mempertimbangkan fakta bahwa kita biasanya berurusan dengan implementasi yang ditandatangani dari sejumlah ukuran dalam bahasa / kerangka kerja, mari kita pertimbangkan signed 16
bilangan bulat mulai dari -(2^15) to 2^15 -1
(nanti kita akan melihat bagaimana memperluas bahkan ouput untuk menjangkau rentang yang ditandatangani). Karena a
dan b
harus positif, mereka berkisar dari 0 to 2^15 - 1
.
Fungsi pemasangan penyanyi :
Pemetaan untuk dua bilangan bulat paling banyak ditandatangani 16 bit (32767, 32767) akan menjadi 2147418112 yang hanya sedikit dari nilai maksimum untuk bilangan bulat 32 bit yang ditandatangani.
Sekarang fungsi Szudzik :
(32767, 32767) => 1073741823, jauh lebih kecil ..
Mari memperhitungkan bilangan bulat negatif. Itu di luar pertanyaan awal yang saya tahu, tetapi hanya menguraikan untuk membantu pengunjung masa depan.
Fungsi pemasangan penyanyi :
A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
(A + B) * (A + B + 1) / 2 + A;
(-32768, -32768) => 8589803520 yang merupakan Int64. Output 64 bit untuk input 16 bit mungkin sangat tidak dapat diampuni !!
Fungsi Szudzik :
A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
A >= B ? A * A + A + B : A + B * B;
(-32768, -32768) => 4294967295 yaitu 32 bit untuk rentang yang tidak ditandatangani atau 64 bit untuk rentang yang ditandatangani, tetapi masih lebih baik.
Sekarang semua ini sementara output selalu positif. Di dunia yang ditandatangani, akan lebih menghemat ruang jika kita bisa mentransfer setengah output ke sumbu negatif . Anda bisa melakukannya seperti ini untuk Szudzik:
A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
C = (A >= B ? A * A + A + B : A + B * B) / 2;
a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
(-32768, 32767) => -2147483648
(32767, -32768) => -2147450880
(0, 0) => 0
(32767, 32767) => 2147418112
(-32768, -32768) => 2147483647
Apa yang saya lakukan: Setelah menerapkan bobot 2
pada input dan melalui fungsi, saya kemudian membagi ouput dengan dua dan mengambil beberapa dari mereka ke sumbu negatif dengan mengalikan dengan -1
.
Lihat hasilnya, untuk input apa pun dalam kisaran 16
nomor bit yang ditandatangani , outputnya berada dalam batas 32
integer bit yang ditandatangani yang keren. Saya tidak yakin bagaimana cara yang sama untuk fungsi pemasangan Cantor tetapi tidak mencoba sebanyak tidak efisien. Selain itu, lebih banyak perhitungan yang terlibat dalam fungsi pemasangan Cantor berarti lebih lambat .
Berikut ini adalah implementasi C #.
public static long PerfectlyHashThem(int a, int b)
{
var A = (ulong)(a >= 0 ? 2 * (long)a : -2 * (long)a - 1);
var B = (ulong)(b >= 0 ? 2 * (long)b : -2 * (long)b - 1);
var C = (long)((A >= B ? A * A + A + B : A + B * B) / 2);
return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}
public static int PerfectlyHashThem(short a, short b)
{
var A = (uint)(a >= 0 ? 2 * a : -2 * a - 1);
var B = (uint)(b >= 0 ? 2 * b : -2 * b - 1);
var C = (int)((A >= B ? A * A + A + B : A + B * B) / 2);
return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}
Karena perhitungan menengah dapat melebihi batas 2N
integer yang ditandatangani, saya telah menggunakan 4N
tipe integer (pembagian terakhir dengan 2
mengembalikan hasilnya ke 2N
).
Tautan yang saya berikan pada solusi alternatif menggambarkan grafik fungsi yang memanfaatkan setiap titik di ruang angkasa. Sungguh menakjubkan melihat bahwa Anda dapat secara unik menyandikan sepasang koordinat ke angka tunggal secara terbalik! Dunia angka yang ajaib !!