Quicksorting alphabetically and by character length - c++

I am currently writing a program that reads a pretty large text file and sorts the text file alphabetically and by character length. i implemented a quicksort to do this. the problem that im having and hopefully will get some clarity on is that i have two methods for quciksorting. One which is quickSortLen here is the code
void SortingCompetition::quickSortLen(vector<char*>& words, int left, int right){
int i, j, middle, underMiddle, overMiddle;
char* pivot;
//Median of FIVE pivot point
i = left;
j = right;
middle = left + (right - left) / 2;
underMiddle = left + (middle - left) / 2;
overMiddle = middle + (right - middle) / 2;
//Right and Left
if(strlen(words[right]) < strlen(words[left]))
{
swap(words[right], words[left]);
}
// 4/5 and left
if(strlen(words[overMiddle]) < strlen(words[left]))
{
swap(words[overMiddle], words[left]);
}
//Middle and Left
if(strlen(words[middle]) < strlen(words[left]))
{
swap(words[middle], words[left]);
}
// 2/5 and Middle
if(strlen(words[underMiddle]) < strlen(words[left]))
{
swap(words[underMiddle], words[left]);
}
//right and 4/5
if(strlen(words[right]) < strlen(words[underMiddle]))
{
swap(words[right], words[underMiddle]);
}
//Right and Middle
if(strlen(words[overMiddle]) < strlen(words[underMiddle]))
{
swap(words[overMiddle], words[underMiddle]);
}
//Middle and UnderMiddle
if(strlen(words[middle]) < strlen(words[underMiddle]))
{
swap(words[middle], words[underMiddle]);
}
//Right and Middle
if(strlen(words[right]) < strlen(words[middle]))
{
swap(words[right], words[middle]);
}
//OverMiddle and Middle
if(strlen(words[overMiddle]) < strlen(words[middle]))
{
swap(words[overMiddle], words[middle]);
}
//Right and OverMiddle
if(strlen(words[right]) < strlen(words[overMiddle]))
{
swap(words[right], words[overMiddle]);
}
//PIVOT POINT ESTABLISHED
pivot = words[middle];
//Partition
while (i <= j)
{
//Check from start
while (strlen(words[i]) < strlen(pivot))
{
++i;
}
//Check from end
while (strlen(words[j]) > strlen(pivot))
{
--j;
}
//Switch
if(i <= j)
{
swap(words[i], words[j]);
++i;
--j;
}
}
//Recursion
if (left < j)
{
quickSortLen(words, left, j);
}
if(i < right)
{
quickSortLen(words, i, right);
}
}
and than i have quickSortAlph here is the code for that
void SortingCompetition::quickSortAlph(vector<char*>& words, int left, int right){
int i, j, middle, underMiddle, overMiddle;
char* pivot;
int x = 1;
//Median of FIVE pivot point
i = left;
j = right;
middle = left + (right - left) / 2;
underMiddle = left + (middle - left) / 2;
overMiddle = middle + (right - middle) / 2;
//Right and Left
if(strcmp(words[right], words[left]) < 0)
{
swap(words[right], words[left]);
}
// 4/5 and left
if(strcmp(words[overMiddle], words[left]) < 0)
{
swap(words[overMiddle], words[left]);
}
//Middle and Left
if(strcmp(words[middle], words[left]) < 0)
{
swap(words[middle], words[left]);
}
// 2/5 and Middle
if(strcmp(words[underMiddle], words[left]) < 0)
{
swap(words[underMiddle], words[left]);
}
//right and 4/5
if(strcmp(words[right], words[underMiddle]) < 0)
{
swap(words[right], words[underMiddle]);
}
//Right and Middle
if(strcmp(words[overMiddle], words[underMiddle]) < 0)
{
swap(words[overMiddle], words[underMiddle]);
}
//Middle and UnderMiddle
if(strcmp(words[middle], words[underMiddle]) < 0)
{
swap(words[middle], words[underMiddle]);
}
//Right and Middle
if(strcmp(words[right], words[middle]) < 0)
{
swap(words[right], words[middle]);
}
//OverMiddle and Middle
if(strcmp(words[overMiddle], words[middle]) < 0)
{
swap(words[overMiddle], words[middle]);
}
//Right and OverMiddle
if(strcmp(words[right], words[overMiddle]) < 0)
{
swap(words[right], words[overMiddle]);
}
//PIVOT POINT ESTABLISHED
pivot = words[middle];
//Partition
while (i <= j)
{
//if((strcmp(words[i], pivot) < 0) && (strcmp(words[j], pivot) < 0)
//Check from start
while (strcmp(words[i], pivot) < 0)
{
++i;
}
//Check from end
while (strcmp(words[j], pivot) > 0)
{
--j;
}
//Switch
if((i <= j))
{
swap(words[i], words[j]);
++i;
--j;
}else{
i++;
j--;
}
}
//Recursion
if (left < j)
{
quickSortAlph(words, left, j);
}
if(i < right)
{
quickSortAlph(words, i, right);
}
}
both work as they should but im having trouble combining the two because a word like august is going to have a less ascii value than bravo but the length is of bravo is less than august. any suggestions on how to go about combining the two?

Do you really need to write your own quick sort? If you don't the you could use std::sort with a custom compare functor.
struct string_cmp
{
bool operator()(const std::string& lhs, const std::string& rhs)
{
if (lhs.size() == rhs.size())
return lhs < rhs;
else
return lhs.size() < rhs.size();
}
};
// and then we call sort on the container
std::sort(container_name.begin(), container_name.end(), string_cmp());

Related

Quick Sort with Insertion Sort

I've been working on this code for hours. The goal is to write an optimized QuickSort (with Insertion sort) on an array of pointers (which point to objects that can be compared). Insertion sort is supposed to be used with array sizes < 4.
So far, I have insertion sort working when I pass in an array < 4.
The quicksort is supposed to use the middle index as a pivot, and move everything < the pivot to the left of pivot, and everything > the pivot to the right of pivot.
I'm not even sure my overall approach to quickSort is correct. This is my first attempt at writing a quick sort. I could really use a nudge in the right direction here. The code that's commented out is something I've already tried.
If anything is unclear, let me know. Thanks for the help!
void quickSort(Comparable ** array, int fromIndex, int toIndex)
{
while (fromIndex < toIndex)
{
if ((toIndex - fromIndex +1 ) < 4)
{
insertionSort(array, fromIndex, toIndex);
break;
}
else
{
int pivotIndex = partition(array, fromIndex, toIndex);
quickSort(array, fromIndex, pivotIndex - 1);
quickSort(array, pivotIndex + 1, toIndex);
}
}
}
int partition(Comparable ** array, int fromIndex, int toIndex)
{
//Comparable *front = array[fromIndex+1];
int midIndex = (toIndex + fromIndex) / 2;
//int frontIndex = fromIndex;
//Comparable *back = array[toIndex - 1];
//int backIndex = toIndex - 1;
//Comparable *compare = front;
//int compareIndex = frontIndex;
SortFirstMiddleLast(array, fromIndex, midIndex, toIndex);
swap(array, midIndex, toIndex - 1);
int pivotIndex = toIndex - 1;
Comparable * pivot = array[pivotIndex];
int indexLeft = fromIndex + 1;
int indexRight = toIndex - 2;
bool sortFinished = false;
while (*array[indexLeft] < *pivot)
{
indexLeft++;
}
while (*array[indexRight] > *pivot)
{
indexRight--;
}
if ((*array[indexLeft] >= *pivot) && (*array[indexRight] <= *pivot))
{
if (indexLeft < indexRight)
{
swap(array, indexLeft, indexRight);
indexLeft++;
indexRight--;
sortFinished = true;
}
}
if (sortFinished == true)
{
swap(array, pivotIndex, indexLeft);
pivotIndex = indexLeft;
return pivotIndex;
}
// ++frontIndex; // advance to next element
// while (*array[frontIndex] < *array[backIndex])
// {
// // search forward for out of order element
// while ((*array[frontIndex] < *array[backIndex]) && (*array[fromIndex] > *array[frontIndex]))
// ++frontIndex;
// //search backward for out of order element
// while ((*array[frontIndex] < *array[backIndex]) && (*array[compareIndex] <= *array[backIndex]))
// --backIndex;
// swap(array, frontIndex, backIndex);
// }
// //insert mid position comparison element
// if (*array[compareIndex] >= *array[frontIndex])
// {
// swap(array, fromIndex, frontIndex);
// returnValue = frontIndex;
// }
// else
// {
// swap(array,fromIndex, (frontIndex - 1));
// returnValue = (frontIndex - 1);
// }
// return returnValue;
}
void swap(Comparable ** array, int swapIndex1, int swapIndex2)
{
Comparable * temp = array[swapIndex1];
array[swapIndex1] = array[swapIndex2];
array[swapIndex2] = temp;
}
void SortFirstMiddleLast(Comparable ** array, int fromIndex, int midIndex, int toIndex)
{
// first must be less than mid, must be less than last
if (*array[fromIndex] > *array[midIndex])
{
swap(array, fromIndex, midIndex);
}
if (*array[fromIndex] > *array[toIndex - 1])
{
swap(array, fromIndex, toIndex - 1);
}
if (*array[midIndex] > *array[toIndex - 1])
{
swap(array, midIndex, toIndex - 1);
}
}
void insertionSort(Comparable ** array, int fromIndex, int toIndex)
{
for (unsigned i = fromIndex + 1; i < toIndex; i++)
{
for (unsigned j = i; j > 0; j--)
{
if (*array[j] < *array[j - 1])
{
swap(array, j, j-1);
}
else
break;
}
}
}

Why would non-recursion method takes more time than recursion?

Take quick sort as an example, both recursion and non-recursion methods are listed below.
I think both methods actually implement the same algorithm, as a stack is used to simulate the recursion process in non-recursion method.
However, I got AC with recursion method but Time Limit Exceeded with non-recursion method after 85% test cases passed.
So, any problem with my non-recursion method or there is a time complexity difference between two methods?
THX!
// non-recursion
void sortIntegers(vector<int> &A) {
if (A.empty()) {
return;
}
stack<pair<int, int>> ranges;
ranges.push(pair<int, int>(0, A.size() - 1));
while (!ranges.empty()) {
pair<int, int> r = ranges.top();
ranges.pop();
int mid = A[r.second],
left = r.first,
right = r.second - 1;
if (r.first >= r.second) {
continue;
}
while (left < right) {
while (A[left] < mid && left < right) {
left++;
}
while (A[right] >= mid && left < right) {
right--;
}
swap(A[left], A[right]);
}
if (A[left] < A[r.second]) {
left++;
} else {
swap(A[left], A[r.second]);
}
ranges.push(pair<int, int>(0, left - 1));
ranges.push(pair<int, int>(left + 1, r.second));
}
// recursion
void sortIntegers(vector<int> &A) {
quick(A, 0, A.size() - 1);
}
void quick(vector<int> & A, int start, int end) {
if (start >= end) {
return;
}
int mid = A[end], //5
left = start, // 0
right = end - 1; //3
while (left < right) {
while (A[left] < mid && left < right) {
left++;
}
while (A[right] >= mid && left < right) {
right--;
}
swap(A[left], A[right]);
}
if (A[left] >= A[end]) {
swap(A[left], A[end]);
}else {
left++;
}
quick(A, start, left - 1);
quick(A, left + 1, end);
}
At first glance, you have at the bottom of your loop:
ranges.push(pair<int, int>(0, left - 1));
ranges.push(pair<int, int>(left + 1, r.second));
To me that should be
ranges.push(pair<int, int>(r.first, left - 1));
ranges.push(pair<int, int>(left + 1, r.second));

Recursively mapping mines on a minesweeper board

I have been trying to make a minesweeper game where given coordinates for a cell it will recursively reveal adjacent cells until a cell adjacent to a bomb is found. I have a method that given coordinates x and y calculates how many mines are surrounding it.
// Counts how many mines are adjacent to a given coordinate cell if any
void board::mineCount(int x, int y) {
// North
if (y > 0) {
if (board[x][y - 1].hasMine) {
board[x][y].mineCount++;
}
}
// South
if (y < dimensions[1] - 1) {
if (board[x][y + 1].hasMine) {
board[x][y].mineCount++;
}
}
// East
if (x < dimensions[0] - 1) {
if (board[x + 1][y].hasMine) {
board[x][y].mineCount++;
}
}
// West
if (x > 0) {
if (board[x - 1][y].hasMine) {
board[x][y].mineCount++;
}
}
// North East
if (x < dimensions[0] - 1 && y > 0) {
if (board[x + 1][y - 1].hasMine) {
board[x][y].mineCount++;
}
}
// North West
if (x > 0 && y > 0) {
if (board[x - 1][y - 1].hasMine) {
board[x][y].mineCount++;
}
}
// South East
if (x < dimensions[0] - 1 && y < dimensions[1] - 1) {
if (board[x + 1][y + 1].hasMine) {
board[x][y].mineCount++;
}
}
// South West
if (x > 0 && y < dimensions[1] - 1) {
if (board[x - 1][y + 1].hasMine) {
board[x][y].mineCount++;
}
}
}
Each cell is a struct which has a mineCount field that gets incremented by 1 each time a mine is found adjacent to it. I am having trouble figuring out where my recursion logic would go. I tried doing something like:
// North
if (y > 0) {
if (board[x][y - 1].hasMine) {
board[x][y].mineCount++;
} else {
minecount(x, y-1);
}
}
for each position but to no avail. Any pointers would be appreciated.
The recursion shouldn't be a part of the code that performs the mine count itself. It should be part of the function that's responsible for revealing nearby tiles.
int get_adjacent_mine_count(point p) {
int mine_count = 0;
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
point this_point(p.x + i, p.y + j);
//is_inside_board checks to see if the point's coordinates are less than 0
//or greater than the board size
if(!is_inside_board(board, this_point)) continue;
//We ignore the center tile
if(i == 0 && j == 0) continue;
if(board(this_point).hasMine)
mine_count++;
}
}
return mine_count;
}
void reveal_tiles(point p) {
//We shouldn't throw if the recursion is correct
if(board(p).hasMine) throw Explosion("Stepped on a Mine!");
//Single call to previously defined function
int num_of_adjacent_mines = get_adjacent_mine_count(p);
//I'm assuming this gets initialized to -1 beforehand
board(p).revealed = num_of_adjacent_mines;
if(num_of_adjacent_mines == 0) {
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
point this_point(p.x + i, p.y + j);
if(!is_inside_board(board, this_point)) continue;
if(i == 0 && j == 0) continue;
if(board(this_point).revealed == -1)
reveal_tiles(this_point);
}
}
}
}
I'm going to strongly recommend you write a simple Matrix class to represent board, which my code implies you've done, because that's a much more robust solution than just trying to interact with a 2D array the C-style way you're doing it.

Partition Sorting issue

I am trying to do a quick sorting. But I have some problem with it. It was supposed to change this array:
{ 1,9,8,7,6,5,4,3,2,10 }
When it receives the arguments left = 0, right = 4 and pivotIndex = 2, to this one:
{ 7,6,1,8,9,5,4,3,2,10 }
But it is actually changing the array to this one:
{ 1,6,7,8,9,5,4,3,2,10 }
I also get this problem if I try to partition this array:
{ 7,6,1,8,9,5,4,3,2,10 }
with arguments right = 9, left = 4 and pivotIndex = 2, to this array:
{ 7,6,1,8,9,2,3,5,4,10 }
I am actually changing to this array:
{ 7,6,1,8,9,2,3,10,5,4 }
Code:
int QS::partition(int left, int right, int pivotIndex)
{
if (my_array == NULL)
return -1;
if (elements <= 0 || capacity <= 0)
return -1;
if (left < 0 || right < 0)
return -1;
else if (right - left <= 1)
return -1;
if (right > elements - 1)
return -1;
if (!(pivotIndex <= right) || !(pivotIndex >= left))
return -1;
int first = pivotIndex;
int last;
if (first == right)
last = left;
else
last = right;
int up = first + 1;
int down = last - 1;
do{
while (!(up != last - 1) || !(my_array[up] <= my_array[first]))
up++;
while (!(my_array[down] > my_array[first]) || !(down != first))
down--;
if (up < down)
swap(up, down);
} while (up < down);
swap(first, down);
return down;
}
I was told to use this algorithm:
But I could not make it work with this algorithm, the closest I got to the result I was told to get, was with the code I am showing you guys.
Can anyone help me? Thank you.

Different results getting array element inside while condition vs outside

I've been working on this quicksort code for a while now and cant figure out why I get different results based on where I get an array value. If I get the value of pivot outside of my loop it works fine, inside the loop it does not.
I've highlighted the difference between each function with some /*This works/doesnt*/ comments.
#include <stdio.h>
void quicksort(int * x, int left_limit, int right_limit) {
int left = left_limit;
int right = right_limit;
int pivot = x[(right + left) / 2]; /* This works */
while (left <= right) {
while (x[left] < pivot) { left++; } /* This works */
while (x[right] > pivot){ right--; } /* This works */
if (left <= right) {
int temp = x[left];
x[left] = x[right];
x[right] = temp;
left++;
right--;
}
}
if (left_limit < right)
quicksort(x, left_limit, right);
if (left < right_limit)
quicksort(x, left, right_limit);
}
void quicksortBROKEN(int * x, int left_limit, int right_limit) {
int left = left_limit;
int right = right_limit;
int pivot = (right + left) / 2; /* This doesnt */
while (left <= right) {
while (x[left] < x[pivot]) { left++; } /* This doesnt */
while (x[right] > x[pivot]){ right--; } /* This doesnt */
if (left <= right) {
int temp = x[left];
x[left] = x[right];
x[right] = temp;
left++;
right--;
}
}
if (left_limit < right)
quicksort(x, left_limit, right);
if (left < right_limit)
quicksort(x, left, right_limit);
}
int main() {
int x[] = {0,2,1,4,3,5,6,3,7,8,4,3,7,8};
quicksort(x, 0, 13);
for (int i = 0; i < 14; i++) {
printf("%d, ", x[i]);
}
printf("\n");
return 0;
}
What is wrong with the broken function?
In the broken version the value of the pivot (as opposed to its location) changes over the course of the function.
Debugger would probably show it to you best, but there is a distinct difference between the functions.
The first one takes a value from the array to the variable and doesn't change it.
The second one takes a position and compares the value on that position in the array each time, while modifying the array. If the array is modified on the position that is stored, naturally the comparisons differ.