Athena
Athena

Reputation: 320

Partitioning algorithm issue with iterative quicksort method

Short version of original question: I am trying to convert this example: http://programmertech.com/program/cpp/quick-sort-recursive-and-iterative-in-c-plus-plus of iterative quicksort to use vectors rather than arrays and begin simplifying a few things. Originally the direct conversion failed, so I tried through it line by line to get a better understanding, but my logic is stuck and broken.

EDIT: Deleted everything from the question, providing a minimal (not quite working) example of what I'm attempting. This is everything I have so far. I have worked through this on paper by hand, and the more I've touched it the worse it gets, and now gets stuck in an infinite loop (originally wasn't sorting correctly).

Here is my thinking: getMedian as I've written it should swap the pivot value, and the left and right values so that they are ordered: left <= med <= right. When we go to the while (right > left) loop in the partition algorithm, it should keep swapping elements to put all of those greater than the pivot to the right of it, and those less to the left. The stack keeps a track of the Sub(vectors) (in this case) which need to be partitioned still. But that doesn't seem to be working. I feel as if I've missed something very important to this working.

#include <iostream>
#include <vector>

class QuickSort {
public:
    QuickSort(std::vector<int> toBeSorted) : toBeSorted(toBeSorted) {}
    void sortVector();
    void print();
private:
    int partition(int left, int right);
    int getMedian(int left, int right);

    std::vector<int> toBeSorted;
};

// Iterative method using a stack
void QuickSort::sortVector() {
    int stack[toBeSorted.size()];
    int top = 0;
    stack[top++] = toBeSorted.size() - 1;
    stack[top++] = 0;

    int left, right, pivIndex;

    while (top > 0) {
        // Popping values for subarray
        left = stack[--top];
        right = stack[--top];
        pivIndex = partition(left, right);

        if (pivIndex + 1 < right) {
            stack[top++] = right;
            stack[top++] = pivIndex+1;
        }

        if (pivIndex - 1 > left) {
            stack[top++] = pivIndex-1;
            stack[top++] = left;
        }
    }
}

int QuickSort::partition(int left, int right) {
    int pivotValue = getMedian(left, right);

    if (right - left > 1) {
    while (right > left) {
        while (toBeSorted[left] < pivotValue) { left++; }
        while (toBeSorted[right] > pivotValue) { right--; }

        if (toBeSorted[right] < toBeSorted[left]) {
            std::swap(toBeSorted[right], toBeSorted[left]);
            left++;
            right--;
        }
    }
    } else {
        if (toBeSorted[right] < toBeSorted[left]) {
            std::swap(toBeSorted[right], toBeSorted[left]);
        }
    }
    return 0;
}

int QuickSort::getMedian(int left, int right) {
    int med = (right - left)/2;
    // if there are an even number of elements, instead of truncating
    // goto the rightmost value.
    if ((right - left)%2 != 0) {
        med = (right-left)/2 + 1;
    }

    // Organise the elements such that 
    // values at indexes: left <= med <= right.
    if (toBeSorted[med] < toBeSorted[left]) {
        std::swap(toBeSorted[left], toBeSorted[med]);
    }
    if (toBeSorted[right] < toBeSorted[left]) {
        std::swap(toBeSorted[left], toBeSorted[right]);
    }
    if (toBeSorted[right] < toBeSorted[med]) {
        std::swap(toBeSorted[right], toBeSorted[med]);
    }

    return toBeSorted[med];
}

void QuickSort::print() {
    for (int i = 0; i != toBeSorted.size(); i++) {
        std::cout << toBeSorted[i] << ",";
    }
    std::cout << std::endl;
}

int main() {
    std::vector<int> values = {5, 8, 7, 1, 2, 5, 3};
    QuickSort *sorter = new QuickSort(values);
    sorter->sortVector();
    sorter->print();
    return 0;
}

Upvotes: 0

Views: 267

Answers (2)

Skand Kulshrestha
Skand Kulshrestha

Reputation: 1

In the first inner while loop, use low++ instead of lower++ and change the return type of function to int.

Upvotes: 0

Ali Soltani
Ali Soltani

Reputation: 9927

In partition method, you shouldn't swap(data[low], data[high]) in every iteration. Your mistake is this portion. You can do it like this:

void partition(int left, int right) {
  // listOfNums is a vector
  int middle = getMidPiv(left, right);
  int low = left;
  int high = right-1;

  while (low < high) {
    while (listOfNums[low] < middle) {
      lower++;
    }

    while (listOfNums[high] > middle) {
      high--;
    }

    if (low < high) {
       swap(data[low], data[high]);
       low++;
       high--;
    }
  }

  // swap(data[low], data[high]); it is incorrect
  return low;
}

Upvotes: 1

Related Questions