Помогите с быстрой сортировкой
Необработанное исключение по адресу 0x7754641B (ntdll.dll) в Быстрая сортировка.exe: 0xC00000FD: Stack overflow (параметры: 0x00000001, 0x00E02FFC)
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <fstream>
#include <cmath>
#include <ctime>
using namespace std;
vector <int> qsor(vector <int> arr) {
vector<int> left;
vector<int> right;
int mid = arr[float((0 + arr.size()) / 2)];
for (int i = 0; i < arr.size(); i++)
{
if (arr[i] <= mid)
left.push_back(arr[i]);
if (arr[i] > mid)
right.push_back(arr[i]);
}
if (left.size() != 0)
left = qsor(left);
if (right.size() != 0)
right = qsor(right);
return(arr);
}
int main()
{
setlocale(LC_ALL, "rus");
vector <int> ttemp1 = { 1, 8, 5, 7, 3, 2, 6 };
vector <int> ttemp2;
ttemp2 = qsor(ttemp1);
for (int i = 0; i < ttemp2.size(); i++)
cout << ttemp2[i] << " ";
cout << endl;
system("pause");
}
Ответы (2 шт):
У вас идет переполнение стека из-за того что у вас рекурсия не останавливается, В интернете полно готовых решений по быстрой сортировке, например вот https://prog-cpp.ru/sort-fast/ можете посмотреть и сравнить что у вас не так
#include <stdio.h>
#include <stdlib.h>
#define SIZE 20
// Функция быстрой сортировки
void quickSort(int *numbers, int left, int right)
{
int pivot; // разрешающий элемент
int l_hold = left; //левая граница
int r_hold = right; // правая граница
pivot = numbers[left];
while (left < right) // пока границы не сомкнутся
{
while ((numbers[right] >= pivot) && (left < right))
right--; // сдвигаем правую границу пока элемент [right] больше [pivot]
if (left != right) // если границы не сомкнулись
{
numbers[left] = numbers[right]; // перемещаем элемент [right] на место разрешающего
left++; // сдвигаем левую границу вправо
}
while ((numbers[left] <= pivot) && (left < right))
left++; // сдвигаем левую границу пока элемент [left] меньше [pivot]
if (left != right) // если границы не сомкнулись
{
numbers[right] = numbers[left]; // перемещаем элемент [left] на место [right]
right--; // сдвигаем правую границу вправо
}
}
numbers[left] = pivot; // ставим разрешающий элемент на место
pivot = left;
left = l_hold;
right = r_hold;
if (left < pivot) // Рекурсивно вызываем сортировку для левой и правой части массива
quickSort(numbers, left, pivot - 1);
if (right > pivot)
quickSort(numbers, pivot + 1, right);
}
int main()
{
int a[SIZE];
// Заполнение массива случайными числами
for (int i = 0; i<SIZE; i++)
a[i] = rand() % 201 - 100;
// Вывод элементов массива до сортировки
for (int i = 0; i<SIZE; i++)
printf("%4d ", a[i]);
printf("\n");
quickSort(a, 0, SIZE-1); // вызов функции сортировки
// Вывод элементов массива после сортировки
for (int i = 0; i<SIZE; i++)
printf("%4d ", a[i]);
printf("\n");
getchar();
return 0;
}
При реализации быстрой сортировки необходимо следить, чтобы длины подмассивов после разбиения были строго меньше чем длина разбиваемого массива.
Передадим массив arr == {1, 3, 2} в вашу сортировку. В качестве опорного значения mid будет выбрано число 3. В подмассив left будут помещены все значения меньше либо равные опорному значению. Т.е. left == {1, 3, 2}. В подмассив right будут помещены все элементы большие, чем опорный элемент. Так как в массиве arr == {1, 3, 2} таких элементов нет, то массив right будет пустым.
Затем функция qsor вызывает себя, передавая в качестве аргумента массив left = {1, 3, 2}. Всё повторяется снова. Функция будет вызывать рекурсивно себя до тех пор, пока не исчерпает стек.
Как вариант можно разбивать исходный массив не на два подмассива, а на три: элементы меньшие опорного, элементы большие опорного и элементы равные опорному. Затем сортировать только меньшие и большие элементы.
#include <vector>
#include <cstddef>
std::vector<int> qsor(std::vector<int> arr)
{
if (arr.size() < 2)
return arr;
std::vector<int> left;
std::vector<int> right;
std::vector<int> middle;
int mid = arr[arr.size() / 2];
for (std::size_t i = 0; i < arr.size(); i++)
{
if (arr[i] < mid)
left.push_back(arr[i]);
else if (arr[i] > mid)
right.push_back(arr[i]);
else
middle.push_back(arr[i]);
}
left = qsor(left);
right = qsor(right);
left.insert(left.end(), middle.begin(), middle.end());
left.insert(left.end(), right.begin(), right.end());
return left;
}
У представленной выше реализации быстрой сортировки есть два серьёзных недостатка.
Во-первых, опасность переполнения стека всё ещё сохраняется. В худшем случае функция сортировки будет разбивать массив длины n на три подмассива с длинами n-1, 1 и 0. При каждом рекурсивном вызове длина большего подмассива может получаться всего на единицу меньше, чем длина сортируемого массива. В таком случае, глубина рекурсии будет пропорциональна длине исходного массива.
Во-вторых, в худшем случае понадобится O(n**2) дополнительной памяти для хранения подмассивов.
Первый недостаток можно решить устранением одного из рекурсивных вызовов. Меньший из подлежащих сортировке подмассивов необходимо сортировать с помощью рекурсивного вызова, а больший подмассив следует сортировать в текущем вызове функции. Тогда максимальная глубина рекурсии в худшем случае будет пропорциональна log(n), где n — длина исходного массива.
Второй недостаток решается сортировкой на месте. Нет никакой необходимости создавать дополнительные подмассивы. Достаточно перемещать элементы сортируемого массива на нужные позиции непосредственно в сортируемом массиве.
К тому же не помешало бы в качестве опорного элемента выбирать что-нибудь посложнее, например, медиану из первого, среднего и последнего элементов. Такая стратегия не исключит вероятность наступления худшего случая, но уменьшит.
#include <utility>
#include <iterator>
#include <functional>
template <typename RandomIt, typename Compare>
void qsort(RandomIt first, RandomIt last, Compare comp)
{
using std::swap;
while (true)
{
auto dist = std::distance(first, last);
if (dist <= 1)
return;
auto& first_val = *first;
auto& last_val = *(last - 1);
if (dist == 2)
{
if (comp(last_val, first_val))
swap(last_val, first_val);
return;
}
auto middle = first + dist / 2;
auto& middle_val = *middle;
if (comp(middle_val, first_val))
swap(middle_val, first_val);
if (comp(last_val, first_val))
swap(last_val, first_val);
if (comp(last_val, middle_val))
swap(last_val, middle_val);
if (dist == 3)
return;
swap(first_val, middle_val);
auto inc_first = first;
auto dec_last = last - 1;
while (true)
{
do
++inc_first;
while (comp(*inc_first, first_val));
do
--dec_last;
while (comp(first_val, *dec_last));
if (inc_first >= dec_last)
break;
swap(*inc_first, *dec_last);
}
if (inc_first - first > last - inc_first)
{
qsort(inc_first, last, comp);
last = inc_first;
}
else
{
qsort(first, inc_first, comp);
first = inc_first;
}
}
}
template <typename RandomIt>
void qsort(RandomIt first, RandomIt last)
{
qsort(first, last, std::less<typename std::iterator_traits<RandomIt>::value_type>());
}