Saya ingin tahu apakah ada logika untuk membalikkan daftar tertaut tunggal dengan hanya menggunakan dua petunjuk.
Berikut ini digunakan untuk membalikkan linked list tunggal dengan menggunakan tiga pointer yaitu p
, q
, r
:
struct node {
int data;
struct node *link;
};
void reverse() {
struct node *p = first,
*q = NULL,
*r;
while (p != NULL) {
r = q;
q = p;
p = p->link;
q->link = r;
}
first = q;
}
Apakah ada alternatif lain untuk membalikkan daftar tertaut? Apa logika terbaik untuk membalikkan daftar tertaut tunggal, dalam hal kerumitan waktu?
Jawaban:
Ada alternatif lain? Tidak, ini sesederhana mungkin, dan tidak ada cara yang berbeda secara fundamental untuk melakukannya. Algoritma ini sudah O (n) waktu, dan Anda tidak bisa lebih cepat dari itu, karena Anda harus memodifikasi setiap node.
Sepertinya kode Anda ada di jalur yang benar, tetapi tidak berfungsi dengan baik di formulir di atas. Ini versi yang berfungsi:
sumber
reverse()
fungsi yang harus disetel terlebih dahulu, saya yakin. Jika tidak, kode asli berfungsi dengan baik saat dicolokkan ke harnes uji yang rapi. Meskipun demikian, Anda mendapatkan +1 dari saya - tetapi penjelasan tentang apa yang Anda anggap sebagai 'kesalahan yang nyata' akan meningkatkan jawaban Anda.Saya benci menjadi pembawa berita buruk, tetapi menurut saya solusi tiga petunjuk Anda tidak benar-benar berfungsi. Ketika saya menggunakannya di harness tes berikut, daftarnya dikurangi menjadi satu node, sesuai output berikut:
Anda tidak akan mendapatkan kerumitan waktu yang lebih baik daripada solusi Anda karena ini adalah O (n) dan Anda harus mengunjungi setiap node untuk mengubah pointer, tetapi Anda dapat melakukan solusi hanya dengan dua pointer tambahan dengan mudah, seperti yang ditunjukkan pada kode berikut:
Kode ini menghasilkan:
yang menurut saya adalah apa yang Anda kejar. Ini benar-benar dapat melakukan ini karena, setelah Anda memuat
first
ke penunjuk yang melintasi daftar, Anda dapat menggunakan kembalifirst
sesuka hati.sumber
first
penunjuk pada daftar tertaut itu sendiri memungkinkan solusi untuk menggunakan hanya 2 penunjuk tambahan , tetapi 3 penunjuk total masih diperlukan untuk ini.first
. Dengan cara yang sama solusi tiga-pointer OP memilikifirst
,p
,q
danr
.sumber
Berikut kode untuk membalikkan daftar sendiri-sendiri terkait dalam C .
Dan di sini ditempel di bawah ini:
sumber
Iya. Saya yakin Anda dapat melakukan ini dengan cara yang sama Anda dapat menukar dua nomor tanpa menggunakan yang ketiga . Cukup lemparkan pointer ke int / long dan lakukan operasi XOR beberapa kali. Ini adalah salah satu trik C yang membuat pertanyaan menyenangkan, tetapi tidak memiliki nilai praktis.
Bisakah Anda mengurangi kompleksitas O (n)? Tidak terlalu. Cukup gunakan daftar tertaut ganda jika Anda merasa perlu urutan terbalik.
sumber
Robert Sedgewick, " Algorithms in C ", Addison-Wesley, Edisi ke-3, 1997, [Bagian 3.4]
Jika itu bukan daftar siklik, maka NULL adalah tautan terakhir.
sumber
Hanya untuk bersenang-senang (meskipun pengoptimalan rekursi ekor harus menghentikannya memakan semua tumpukan):
sumber
Untuk menukar dua variabel tanpa menggunakan variabel sementara,
cara tercepat adalah dengan menuliskannya dalam satu baris
Demikian pula,
menggunakan dua swap
solusi menggunakan xor
solusi dalam satu baris
Logika yang sama digunakan untuk membalik daftar tertaut.
sumber
intptr_t
). Meskipun menarik - menukar cara ini kurang optimal pada sistem modern.Anda membutuhkan penunjuk trek yang akan melacak daftar.
Anda membutuhkan dua petunjuk:
penunjuk pertama untuk memilih simpul pertama. pointer kedua untuk memilih node kedua.
Pengolahan:
Pindahkan Track Pointer
Arahkan simpul kedua ke simpul pertama
Pindahkan penunjuk pertama satu langkah, dengan menetapkan penunjuk kedua ke satu
Pindahkan penunjuk kedua satu langkah, Dengan menetapkan penunjuk Lacak ke kedua
}
sumber
Bagaimana kalau lebih mudah dibaca:
sumber
Ini adalah versi yang lebih sederhana di Java. Itu hanya menggunakan dua petunjuk
curr
&prev
sumber
Cari tahu kerumitan waktu dari algoritme yang Anda gunakan sekarang dan harus jelas terlihat bahwa algoritme tersebut tidak dapat ditingkatkan.
sumber
Saya tidak mengerti mengapa ada kebutuhan untuk kembali ke kepala saat kami menyampaikannya sebagai argumen. Kami melewati kepala daftar tautan kemudian kami dapat memperbarui juga. Di bawah ini adalah solusi sederhana.
sumber
sumber
Tidak, tidak ada yang lebih cepat dari O (n) saat ini yang dapat dilakukan. Anda perlu mengubah setiap node, jadi waktu akan proporsional dengan jumlah elemen dan itulah O (n) yang sudah Anda miliki.
sumber
Menggunakan dua pointer sambil mempertahankan kompleksitas waktu O (n), yang paling cepat dicapai, mungkin hanya dapat dilakukan melalui jumlah casting pointer dan menukar nilainya. Berikut implementasinya:
sumber
Saya memiliki pendekatan yang sedikit berbeda. Saya ingin menggunakan fungsi yang ada (seperti insert_at (index), delete_from (index)) untuk membalikkan daftar (seperti operasi shift kanan). Kompleksitasnya masih O (n) tetapi keuntungannya adalah kode yang lebih banyak digunakan kembali. Lihat metode another_reverse () dan beri tahu saya pendapat Anda semua.
sumber
sumber
sumber
Ya, ada cara yang hanya menggunakan dua petunjuk. Yaitu dengan membuat daftar tertaut baru di mana simpul pertama adalah simpul pertama dari daftar yang diberikan dan simpul kedua dari daftar pertama ditambahkan pada awal daftar baru dan seterusnya.
sumber
Ini versi saya:
dimana
sumber
Saya menggunakan java untuk mengimplementasikan ini dan pendekatannya adalah pengembangan yang digerakkan oleh uji sehingga kasus uji juga dilampirkan.
Kelas Node yang mewakili node tunggal -
Kelas layanan yang mengambil node awal sebagai masukan dan memesannya tanpa menggunakan ruang ekstra.
Dan kasus uji yang mencakup skenario di atas. Harap dicatat bahwa Anda memerlukan stoples junit. Saya menggunakan testng.jar; Anda dapat menggunakan apapun yang Anda suka ..
sumber
Algoritme sederhana jika Anda menggunakan daftar tertaut sebagai struktur tumpukan:
Kinerja mungkin terpengaruh karena pemanggilan fungsi tambahan ke add dan malloc sehingga algoritme pertukaran alamat lebih baik tetapi yang sebenarnya membuat daftar baru sehingga Anda dapat menggunakan opsi tambahan seperti mengurutkan atau menghapus item jika Anda menambahkan fungsi panggilan balik sebagai parameter ke balik.
sumber
Berikut ini adalah pendekatan yang sedikit berbeda, tetapi sederhana di C ++ 11:
Keluarkan di sini
sumber
Berikut ini adalah salah satu implementasi menggunakan 2 pointer (head dan r)
sumber
sizeof(size_t) < sizeof(ListNode*)
... Anda harus menggunakannyastd::uintptr_t
.berikut ini sedikit solusi sederhana ...
sumber
Anda dapat memiliki solusi untuk masalah ini dengan bantuan hanya satu penunjuk tambahan, yang harus statis untuk fungsi sebaliknya. Ini dalam kompleksitas O (n).
sumber
Sebagai alternatif, Anda dapat menggunakan rekursi-
sumber
sumber
sumber