Нэг тоог pivot болгож, түүнээс бага тоонуудыг зүүн тийш, бусдыг нь баруун тийш хуваагаад хоёр талыг дахин ингэж эрэмбэлдэг хурдан арга.
Эхлээд жижиг бодлого
a = [3, 6, 1, 5, 4] array-г эрэмбэлье. Сүүлийн тоо 4-ийг pivot болгоно. 4-өөс бага 3, 1-ийг зүүн тийш, бусдыг нь баруун тийш цуглуулахад [3, 1, 4, 5, 6] болно.
4 эцсийн байрандаа орлоо. Одоо зүүн [3, 1], баруун [5, 6] хэсгийг тус тусад нь яг ингэж эрэмбэлнэ. Хариу: [1, 3, 4, 5, 6].
Энгийн аргаас санаа руу
Merge Sort эхлээд хувааж, гол ажлаа нийлүүлэх үед хийдэг. Quick Sort эсрэгээрээ: эхлээд нэг тоог (pivot) сонгоод, бага тоонуудыг зүүн тийш, бусдыг нь баруун тийш хуваана. Pivot эцсийн байрандаа очих тул дараа нь нийлүүлэх шаардлагагүй.
Хуваах ажлыг (partition) ганц loop хийнэ. i нь дараагийн бага тоо очих байрыг заана. j-ээр тоо бүрийг харж, a[j] < p бол a[i]-тай солиод i-г нэмнэ. Эцэст нь pivot-ыг a[i]-тай солино.
Нэр томьёо ба тэмдэглэгээ
- p
- Pivot-ын утга. Энэ кодод хэсгийн сүүлийн тоо
a[r]. - i
- p-ээс бага тоонууд
a[l]-ээсa[i - 1]хүртэл цугларна. Pivot эцэст ньi-р байранд очно. - partition
- Хэсгийг p-ээс бага ба бусад гэж хоёр хуваах алхам.
- quickSort(l, r)
a[l..r]хэсгийг эрэмбэлдэг recursive function.
Эхэнд: 8 3 6 1 9 2 5. Нэг тоог pivot болгоно. Түүнээс бага тоонуудыг зүүн тийш, бусдыг нь баруун тийш хуваана.
- Space тоглуулах
- ←→ алхам
- −+ хурд
- Энгийн
- Pivot (p)
- p-тэй харьцуулж буй
- Солигдсон
- Байрандаа орсон
- Одоогийн хэсгээс гадуур
Pivot-оор хуваана
Quick Sort нэг тоог pivot болгож сонгоно. Түүнээс бага тоонууд зүүн тийш, бусад нь баруун тийш очно.
Дараа нь юу болох вэ?
Оноо 0 / 00дараалсан зөв, хамгийн их 0
Animation нэг алхам дээр зогсоно. Дараа нь код юу хийх вэ? Таагаад оноо цуглуул! Нэвтрэх хэрэггүй, оноо чинь энэ төхөөрөмж дээр хадгалагдана.
Юунд хэрэгтэй вэ?
Их хэмжээний тоог нэмэлт array-гүйгээр хурдан эрэмбэлэх. Практикт хамгийн өргөн хэрэглэгддэг эрэмбэлэх аргын нэг.
Яаж ажилладаг вэ?
1. Хэсгийн сүүлийн тоо pivot болно: p = a[r]. i = l нь бага тоо очих дараагийн байр. 2. a[l] … a[r − 1] тоо бүрийг p-тэй харьцуулна. a[j] < p бол a[i] ба a[j] байраа сольж, i нэгээр нэмэгдэнэ. 3. Эцэст нь a[i] ба a[r] солигдож, pivot байрандаа орно. 4. Pivot-ын зүүн, баруун хэсгийг яг ингэж эрэмбэлнэ (recursion). Оролт: эхний мөрөнд n, дараагийн мөрөнд n тоо.
Яагаад зөв, хэр хурдан бэ?
Partition дуусахад pivot-оос зүүн талын бүх тоо p-ээс бага, баруун талынх нь p-ээс бага биш. Тиймээс pivot эцсийн байрандаа орсон. Хоёр талыг тус тусад нь эрэмбэлэхэд бүхэл array эрэмбэлэгдэнэ.
Pivot хэсгийг ойролцоогоор тэнцүү хуваавал log₂ n давхар болж, хугацаа O(n log n). Харин эрэмбэлэгдсэн array дээр сүүлийн тоо үргэлж хамгийн их тул хуваалт n - 1 ба 0 болж, O(n²) болно. n = 100 000 бол 5 тэрбум орчим харьцуулалт, хугацаандаа багтахгүй. Нэмэлт санах ой нь зөвхөн recursion-ий гүн.
Түгээмэл алдаа
- Эрэмбэлэгдсэн эсвэл бүх тоо ижил array дээр O(n²) болно. Олимпиадад pivot-ыг санамсаргүй сонгох эсвэл
sort()ашигла. - Муу тохиолдолд recursion-ий гүн n хүрч, stack overflow болж болно.
if (l >= r) return;мөрийг мартвал хоосон эсвэл ганц элементтэй хэсэг дээр recursion хэзээ ч зогсохгүй.- Эцэст нь pivot-ыг
a[i]-тай солихоо мартах. Тэгвэл pivot байрандаа очихгүй, хариу буруу.
Хязгаарын тохиолдол
- n = 1:
quickSort(0, 0)шууд буцна. - Бүх утга ижил:
a[j] < pхэзээ ч үнэн биш тул хуваалт тэнцвэргүй, O(n²). - Эрэмбэлэгдсэн array: pivot үргэлж хамгийн их тоо, хэсэг нэг нэгээр л багасна.
- Хоёр элемент: ганц partition-оор шийдэгдэнэ.
Өөрийгөө шалга
Анхдагч жишээ
[8, 3, 6, 1, 9, 2, 5]дээр эхний partition хийсний дараа pivot 5 аль index-д очих вэ?Хариу харах
3. Түүнээс бага 3, 1, 2 гурван тоо зүүн талд нь орно.
1000 тоотой эрэмбэлэгдсэн array дээр хэдэн харьцуулалт хийх вэ?
Хариу харах
999 + 998 + … + 1 = 499 500.
Гурван дадлага
Hint-ээ нээхээс өмнө өөрөө оролдоорой.
1.
[4, 7, 2, 6, 1, 5]дээр эхний partition-ыг алхам алхмаар хий.Hint харах
p = 5. j бүрт
a[j] < 5эсэхийг шалгаад, тийм болa[i]-тай соль.Хариу ба тайлбар
Үр дүн нь
[4, 2, 1, 5, 7, 6], pivot 5 нь index 3-т орлоо. Зүүн талд[4, 2, 1], баруун талд[7, 6].2.Эрэмбэлэгдсэн array дээр удаашрахгүйн тулд pivot-ыг санамсаргүй сонгодог болго.
Hint харах
Санамсаргүй index дээрх тоог сүүл рүү нь шилжүүлбэл үлдсэн код хэвээр ажиллана.
Хариу ба тайлбар
quickSort-ын эхэнд
int k = l + rand() % (r - l + 1); swap(a[k], a[r]);нэмнэ. Ямар ч оролт дээр дунджаар O(n log n) болно.3.Array-н k дахь хамгийн бага тоог дунджаар O(n) хугацаанд ол (Quickselect).
Hint харах
Partition-ы дараа pivot-ын index-ийг k-тэй харьцуул. Хоёр талыг хоёуланг нь эрэмбэлэх хэрэг бий юу?
Хариу ба тайлбар
Pivot
i-р байранд очсон бол:k == iүед хариуa[i].k < iбол зөвхөн зүүн хэсэгт, үгүй бол зөвхөн баруун хэсэгт үргэлжлүүлнэ. Ганц талаар л явдаг тул дунджаар O(n).
Жишээ
Оролт
7 8 3 6 1 9 2 5
Гаралт
1 2 3 5 6 8 9
Одоо өөрөө бодоод үз
Хичээл
Энэ сэдвийн хичээл удахгүй нэмэгдэнэ.