Two questions about quicksort - c++

I have two questions when learning quicksort currently. The standard code is here(copy from my book):
void Quicksort(int a[], int low, int high){
if(low<high){
int pivotpos=Patrition(a,low,high);
Quicksort(a,low,pivotpos-1);
Quicksort(a,pivotpos+1,high);
}
}
int Patrition(int a[], int low, int high){
int pivot=a[low]; //first elemnent as pivot
while(low<high){
while(low<high&&a[high]>=pivot) --high; //1
a[low]=a[high];
while(low<high&&a[low]<=pivot) ++low; //2
a[high]=a[low];
}
a[low]=pivot;
return low;
}
My questions are in the above code(marked 1 and 2):
a. why the program cannot be performed(core dumped) when I type this in 1:
while(a[high]>=pivot) --high (similarly in 2). It seems that I have to add the condition(low<high) in the second and third while loop or it said core dumped?
b. another question is why there must be a operator= in second and third while loop. I am confused why it won't work when I type while(low<high&& a[high]>pivot (similarly in 2). If I do so, this program will keep looping and never goes to end.
Thanks for your attention. Any suggestion will be highly appreciated.

The reason for having to write low < high in each while-loop is because it first checks the condition for the first while (the big one), starts looping, then it check the condition in while //1 and keeps looping, but during that time, the first while's (the big one) condition is never checked.
Example:
a = 6;
while (a > 5) {
while (a > 3) {
--a;
}
}
In this code, the second loop only stops when a = 3.
As for question b, it's because it never actually reaches the value that needs to be changed, hence never actually sorting it.
Example: If you'd want the loop to stop at a = 3, the following loop would stop one step earlier.
a = 5;
while (a > 4) {
--a;
}
Value a never reaches 3, it stops at a = 4,

Related

C++ time limit exceeded when it doesn't even execute the function

While I was solving a problem in LeetCode, I found something very strange.
I have this line which I assume gives me a time limit exceeded error:
s.erase(i-k, k);
when I comment(//) this line, it doesn't show me time exceed error, but the strange part was, it has never executed even when i didn't comment it.
below is the entire code.
and Here is the problem link.
class Solution {
public:
string removeDuplicates(string s, int k) {
char prev = s[0];
int cnt = 1;
cnt = 1;
for(int i = 1; i < s.size() + 1; i++){
if(s[i] == prev){
cnt++;
} else {
if(cnt == k){
// when input is "abcd" it never comes to this scope
// which is impossible to run erase function.
s.erase(i-k, k);
i = 0;
}
if(i >= s.size()) break;
cnt = 1;
prev = s[i];
}
}
return s;
}
};
When Input is "abcd", it never even go to the if scope where 'erase' function is in.
Although 'erase' function never run, it still affect on the time complexity, and I can't get the reason.
Does anyone can explain this? or is this just problem of LeetCode?
Many online contest servers report Time Exceeding when program encounters critical error (coding bug) and/or crashes.
For example error of reading out of bounds of array. Or dereferencing bad (junk) pointers.
Why Time Exceeded. Because with critical error program can hang up and/or crash. Meaning it also doesn't deliver result in time.
So I think you have to debug your program to find all coding errors, not spending your time optimizing algorithm.
Regarding this line s.erase(i-k, k); - it may crash/hang-up when i < k, then you have negative value, which is not allowed by .erase() method. When you get for example i - k equal to -1 then size_t type (type of first argument of erase) will overflow (wrap around) to value 18446744073709551615 which is defnitely out of bounds, and out of memory border, hence your program may crash and/or hang. Also erase crashes when there is too many chars deleted, i.e. for erase s.erase(a, b) you have to watch that a + b <= s.size(), it is not controlled by erase function.
See documentation of erase method, and don't put negative values as arguments to this method. Check that your algorithm never has negative value i.e. never i < k when calling s.erase(i-k, k);, also never i-k + k > s.size(). To make sure there is no program crash you may do following:
int start = std::min(std::max(0, i-k), int(s.size()));
int num = std::min(k, std::max(0, int(s.size()) - start));
s.erase(start, num);

Why is my for loop running only 2 times instead of 10?

I am trying to find the third highest number in the array with O(n) space and time complexity.
MY program is obviously wrong but that is not the problem.
My for loop in the thirdhighestnum function seem to running only 2 times. I can't seem to find the reason for it. Can anyone help me. Sorry for such basic question I am a beginner here.
#include<iostream>
using namespace std;
int thirdhighestnum(int a[],int size)
{
cout<<" "<<size<<endl;
int first=a[0],second=0,third=0;
for(int i=1;i<size;i++)
{
cout<<a[i]<<";"<<endl;
if(a[i]>first)
{
first=a[i];
if(a[i+1]>first)
{
second=first;
first=a[i+1];
if(a[i+2]>first)
{ third=second;
second=first;
first=a[i+2];
}
}
cout<<i<<endl
return third;
}
}
}
int main()
{ int num,a[10];
cout<<"Enter the elements in the array"<<endl;
for(int i=0;i<10;i++)
cin>>a[i];
cout<<"Third highest number is "<<thirdhighestnum(a,10)<<endl;
return 0;
}
It's the location of your return third statement. The moment any number is larger than the first number, it exits the thirdhighestnum function and returns a value. Put it outside your for loop and it should be fine.
Actually it is executing only one time i.e. the first iteration only. When i=1 then it prints a[1] i.e. 2; after that it prints i i.e. 1 so it appears as 2;1 here you think it is printing 2 numbers.
The main problem is your return third statement which terminates your for loop in first iteration only.
This is known as nth_element and library function can do this for you.
As for why your code fails, there is a flaw in your logic
for(int i=1;i<size;i++)
{
// some code
if(a[i]>first)
{
// some more code
cout<<i<<endl
return third;
}
}
So your code exits the first time a[i] is greater than first.
[edit - After reading comments]
The generic name for this type of algorithm is a QuickSelect. It is unlikely you will find a faster algorithm, as this has been the subject of years of academic study.

C++ ⎼ Two similar functions but performing very differently

I am writing a quicksort program. For that I need to partition the array. The partitioning is done by a function paritionIt(). I wrote a code of partitioning the array which is as follows:
int partition(int beg,int end,double key)
{
int pLeft = beg;
int pRight = end-1;
while(pLeft<pRight)
{
while(array[++pLeft]<key);
while(array[--pRight]>key);
if(pLeft<pRight)
swap(pLeft,pRight);
}
swap(pLeft,end-1);
return pLeft;
}
This block seems to work to work fine when executed in isolation. However, when ran along with the other functions, it seems to generate wrong answer. The following code given to me makes all the problems vanish but it doesn't seem much different from my code.
int partitionIt(int left, int right, double pivot)
{
int leftMark = left; //right of first elem
int rightMark = right - 1; //left of pivot
while(true)
{
while( theVect[++leftMark] < pivot ) //find bigger
; // (nop)
while( theVect[--rightMark] > pivot ) //find smaller
; // (nop)
if(leftMark >= rightMark) //if pointers cross,
break; // partition done
else //not crossed, so
swap(leftMark, rightMark); //swap elements
} //end while(true)
swap(leftMark, right-1); //restore pivot
return leftMark; //return pivot location
} //end partitionIt()
The block seems to be similar to mine but is giving the right answer whereas mine is not. Can you please me by telling what's the difference between partition() and partitionIt().
The difference is where you're breaking out of your looping structure.
In your code, you're making two conditional checks, whereas in the given code, you're only making one.
Assume you've been iterating through the loop for a while. (No pun intended).
You'll hit this code:
if(pLeft<pRight)
swap(pLeft,pRight);
Then you'll hit the bottom of the while loop, come back to the top, and then check again if pLeft<pRight. If this isn't true, we exit the loop.
In the given code, you perform the swap, but then you do the following:
while( theVect[++leftMark] < pivot ) //find bigger
; // (nop)
while( theVect[--rightMark] > pivot ) //find smaller
; // (nop)
You then check to see if you break out of the loop.
This seems to be where the difference lies.
Edit: To clarify - what happens if while(pLeft>=pRight) when you first enter the loop?
In the given code, you continue through the while loop until it breaks, but in your code, you never enter the body of the loop.
The only thing I see immediately is that the functions will
behave differently if called with left + 1 == right: your
function will not enter the loop, but will return beg; the
function from the book will enter the loop, thus incrementing
leftMark and decrementing rightMark before doing the final
swap and returning leftMark.

C++ Sieve of Eratosthenes finding 3 too many primes

I have a programming assignment to write a program in C++ that finds all primes less than n (user input). One half of the assignment involves the Sieve of Eratosthenes. My code is working (read: assignment is complete), but before I edited the output, it was unconditionally printing out n-3, n-2, and n-1 as primes even if they were not prime. I'm not sure why this is happening. I'd appreciate a bit of feedback and ideas as to why the program is acting the way it is. Here is the unaltered code:
Please note that I am using a ListNode class and a LinkedList class, both of which are fully functional. EDIT: partial main added; notice the second item in the for loop is size-3. If it's left at size, the program outputs 3 extra non-primes.
int main()
{
for(int i = 0; i<my_list.size()-3; i++)
{
if(marked[i]==true)
cout<<my_list[i]<<"\n";
}
}
void eratosthenes(int item)
{
bool run=true;
int p=2, count=0;
for(int i=2; i<=item; i++)
{
my_list.append(i); // Entire list is filled with integers from 2 to n
marked.append(true); // Entire list is filled with true entries
}
while(run==true&&(2*p)<item)
{
count = 0;
int i = (2*p);
do {
marked[i-2]=false; // marked values are false and not prime
i+=p;
} while(i<item-2);
for(int i=0; i<item-2; i++) // i starts at 0 and increments by 1
{ // each time through the loop
if(my_list[i]>p)
{
if(marked[i]==true) // If a value stored in a node is true
{ // (prime), it becomes the new p.
p=my_list[i]; // The loop is then broken.
break;
}
}
}
for(int j=1; j<item-2; j++)
{
if(marked[j]==false)
{
count=1;
}
}
if(count==0)
run=false;
}
Complete method
void Eratosthenes(int upperBound)
{
bool Prime[upperBound];
for(int i = 0;i<upperBound;i++)
Prime[i]=true;
for (int i = 2; i <= sqrt(upperBound); i++)
{
if (Prime[i])
{
for (int j = i * 2; j < upperBound; j += i)
Prime[j] = false;
}
}
for(int i=2;i<upperBound;i++)
{
if(Prime[i]==true)
cout<<i<<" ";
}
}
From your code:
do{
marked[i-2]=false;//marked values are false and not prime
i+=p;
}while(i<item-2);
This loop is responsible for going through all numbers i that are integer multiples of the prime number p and marking them not prime, as I understand. Why are you stopping on the condition i < item - 2? This would be fine if i were your index for the my_list and marked lists, but in this case it's not; it's the actual number you're marking not prime. I suspect this is why you're getting numbers near your limit (item) that are marked as prime—your loop here exits before i ever gets to those numbers!
By the way, you could do this as a for loop instead, which would be easier to read. The for loop has the meaning "go through each element in a set" (whether that's consecutive integers, or every nth integer, or elements in an array/list/deque, etc.), so a programmer reading your code knows that immediately and doesn't have to figure it out from your while loop.
// mark every multiple of the current prime as not prime
for(int i = 2*p; i < item - 2; i += p)
{
marked[i-2] = false;
}
(This is the same as your original code, no fixes applied).
Some general comments to improve your algorithm/code:
Try using more descriptive variable names. Your use of i two times to mean different things is confusing, and in general single letters don't mean much as to what the variable represents (although sometimes they're sufficient, e.g. a for loop where i is the index of a list/array).
Also, you're looping over your list a lot more than you need to. The minimum a sieve of Eratosthenes algorithm needs is two nested for loops (not including initializing a list/array to all true).
One example of where you're doing more work than necessary is that you're looping starting from index 0 to find the next p to use—instead of just remembering where your current p is and starting from there. You wouldn't even need to check my_list[i] > p in that case, since you know you'd be beyond it to start off. Also, your last loop could break; early and avoid continuing on after it finds a non-prime (and I'm not sure what the point of it is).
Nikola Mitev's second answer is a more efficient and more readable implementation of the sieve (but replace sqrt(upperBound) with upperBound/2 for it to work correctly; the reason for upperBound/2 should be pretty clear from the way the Sieve works), although he didn't really give much comment or explanation on it. The first loop is "go through every number up to upperBound"; inside it, "if the current number is a prime, go through all the multiples of that prime and mark them non-prime". After that innerloop executes, the outer loop continues, going through the next numbers—no need to start from the beginning, or even type out another for loop, to find the next prime.
EDIT: sqrt(upperBound) is correct. I wasn't thinking about it carefully enough.
Why don't you work with array of booleans for simplicity starting from index 2, and when you will print the result, you will print indices with value of true

Count the number of matching elements in two arrays C++

I'm working on a homework assignment for Comp Sci I, and I've tried literally everything I could find on the internet and in my textbook in an attempt to count the number of matching elements in two C++ arrays. I simply can't find a way to make my code count the number of matching elements in two arrays of the same size (same value, same position). For instance, if array1 has 5, 4, 3, 2, 1, and array2 has 1, 2, 3, 4, 5, there is one matching element, the 3. How can I get my code to perform this seemingly simple task?
Couldn't find an answer anywhere. My textbook only shows how to see if the arrays match exactly without counting the number of matches, and I haven't been able to find anyone else with this exact question for C++.
Here's my function so far:
int matchCounter(int lottery[5], int user[5], int matches, int SIZE)
{
int count = 0;
for (count < SIZE; count++;)
{
if (lottery[count] == user[count])
{
matches++;
}
}
return matches;
} // end matchCounter
SIZE is a constant that equals 5, by the way. It would seem that this should work, but every time I run the program, it displays 0 matches, even in there are some matches. If anyone could help me out, I would be forever in your debt. Seriously, there's got to be some incredibly simple thing I'm just not seeing. Thanks for you help in advance.
Your for statement is garbled. Try this:
int matchCounter(int lottery[5], int user[5], int matches, int SIZE)
{
for (int count = 0; count < SIZE; count++)
{
...
For reason why your program always fails: count++ is put in the position of the condition in the for loop, so every time this for loop is executed, count is evaluated and considered to be the condition, and then count is incremented by 1. However, every time count starts from 0 (as in int count = 0;), so the for loop actually never gets executed, and matches remain zero.
EDIT:
From your source code, you're not using your return value, which is also suggested by #jimhark. Change the function signature to:
int matchCounter(int lottery[5], int user[5], int SIZE)
And call with:
matches = matchCounter(lottery, user, 5);
Otherwise, your return value of the function matchCounter is ignored, while int matches only plays the role of a local variable in the function.
Read this about why the matches doesn't work: http://www.cs.utsa.edu/~wagner/CS2213/swap/swap.html (in a similar setting)
Since this is a homework, I will try to point the errors without giving the solution.
The form of a for loop is:
for (INIT; COND; STEP) {
BODY;
}
which is equivalent to:
INIT;
while (COND) {
BODY;
STEP;
}
The way you did, your INIT is count < SIZE, which doesn't do anything. Your "COND" is count++, which returns 0 on the first iteration. As you may know, 0 is false, in the context of a boolean. Therefore, your for loop body is not being executed at all.
Also, you should not pass matches as an argument. It should be a local variable initialized with 0.
Your may not be using your return value. Change sig to:
int matchCounter(int lottery[5], int user[5], int SIZE)
{
matches = 0;
And make sure your're calling with:
matches = matchCounter(lottery, user, 5);
If you need a running sum, use:
matches += matchCounter(lottery, user, 5);
In any case matchCounter doesn't care what running total is, so why pass it in?
Also you may need to sort the lists first.
Maybe this can help:
int matches=0;
for(int i=0;i<ARRAY.SIZE;i++) {
for(int j=0;j<ARRAY.SIZE;j++) {
if(arr1[i]==arr2[j]) {
matches++;
arr2[j]=NULL;
}
}
}