Skip to content

implemented graham scan in C plus plus #616

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 10, 2019

Conversation

AkashDhiman
Copy link
Contributor

I also took the edge case when the algorithm can encounter multiple points with the same polar angle or same minimum y co-ordinate, and sorting is done via cross product itself so I didn't include trigonometric functions to do sorting. this is my first PR, let me know if there is something I can improve upon.

@c252 c252 added the Implementation This provides an implementation for an algorithm. (Code and maybe md files are edited.) label Jun 21, 2019
Copy link
Contributor

@dovisutu dovisutu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution. I'm not a really reviewer, but I reviewed it because I know a quite about c++.
You can correct these things, or you can also wait for the real reviewing.
Thankfully, your code does not have compiling problems (unlike tree_traversal before), but there's a runtime error I didn't mention it here. Maybe tomorrow I'll test it and try to add it?


point origin;

void swap(point &p1, point &p2){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a swap function swap<Type>(Type& left, Type& right) in <algorithm> header. Don't make your own.

p2 = temp;
}

int distSq(point p1, point p2){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As compare is useless, and it only uses in compare, this should also be useless.

double y;
};

point origin;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use a global origin variable. Localize it in grahamScan and as argument of ccwCheck.

Suggested change
point origin;

return ( crossProduct > 0)? -1 : 1;
}

int compare(const void *vp1, const void *vp2){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compare function is totally useless, I think. It's OK to have points colinear, as the one inwards will be replaced.

{
return 0;
}
return ( crossProduct > 0)? -1 : 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unnececcary to return 1,0 or -1. It's not a bool, so we have to compare it again, therefore, why not just return it?
Also, the previous if is useless, too.

Suggested change
return ( crossProduct > 0)? -1 : 1;
return (b.y - a.y) * (c.x - b.x) - (b.x - a.x) * (c.y - b.y);

origin = points[0];

//sorting by polar angle and removing duplicates
qsort(&points[1], points.size() - 1, sizeof(point), compare);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to use sort<_Ranit, _Pr>(const _RanIt _First, const _RanIt _Last, _Pr _Pred) in <algorithm> instead of qsort(void* _Base, size_t _NumOfElements, size_t _SizeOfElements, int (*_CompareFunction)(const void*, const void*) in <corecrt_search.h>.
Also, since compare is useless, the _Pr can be a simple lambda [&](point& a, point& b){return ccwCheck(points[0],a,b)


//sorting by polar angle and removing duplicates
qsort(&points[1], points.size() - 1, sizeof(point), compare);
std::vector<point> pointsSorted;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't needed to create new one. original one is OK to edit

}

//creating the convex hull
std::vector<point> hull;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned, the algorithm shouldn't create a new vector to store hull.

To save memory and expensive append() operations, we ultimately look for points that should be on the hull and swap them with the first elements in the array. If there are Melements on the hull, then the first M elements in our output random distribution of points will be the hull.

@AkashDhiman
Copy link
Contributor Author

AkashDhiman commented Jun 22, 2019 via email

@leios
Copy link
Member

leios commented Jul 6, 2019

Thanks for the review here @dovisutu!

Are you on discord? I apologize if you are there already and I missed you. A lot of discussion happens there.

@dovisutu
Copy link
Contributor

dovisutu commented Jul 6, 2019

Thanks for the review here @dovisutu!
Are you on discord? I apologize if you are there already and I missed you. A lot of discussion happens there.

I'd like to, but I can't login discord here in China...
Maybe try my VPN again...
(It worked, but 3 months ago it broke.)

Copy link
Contributor

@dovisutu dovisutu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second round of reviewing, without testing on my maching.

std::vector<point>::const_iterator first = points.begin();
std::vector<point>::const_iterator last = points.begin()+m;
std::vector<point> hull(first, last);
return hull;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to inline these statements:

Suggested change
return hull;
return std::vector<point>(points.begin(), points.begin() + m);

}
}
m++;
std::swap<point>(points[i],points[m]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't have to specify type. Automatic Type Inference will infers that _Ty is Point.
Also, spacing please.

Suggested change
std::swap<point>(points[i],points[m]);
std::swap(points[i], points[m]);


void print(std::vector<point> points){
std::cout << "points in hull are as follows: \n";
for (size_t i = 0; i < points.size(); i++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to use for with range similar with for each in other languages. Like this:

Suggested change
for (size_t i = 0; i < points.size(); i++) {
for (auto p : points) {

Then use p instead of points[i] below.

@@ -0,0 +1,66 @@
#include<iostream>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please space between #include and header in order to be consistent with other implementations in AAA.

lowIndex = i;
}
}
std::swap<point>(points[0], points[lowIndex]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't have to specify type. Automatic Type Inference will infers that _Ty is Point.

Suggested change
std::swap<point>(points[0], points[lowIndex]);
std::swap(points[0], points[lowIndex]);

point pivot = points[0];

//sorting points by polar angle
sort(points.begin()+1, points.end(), [pivot](point a, point b){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sort is in namespace std.

Suggested change
sort(points.begin()+1, points.end(), [pivot](point a, point b){
std::sort(points.begin()+1, points.end(), [pivot](point a, point b){

std::vector<point> points = {{-5, 2}, {5, 7}, {-6, -12}, {-14, -14}, {9, 9},
{-1, -1}, {-10, 11}, {-6, 15}, {-6, -8}, {15, -9},
{7, -7}, {-2, -9}, {6, -5}, {0, 14}, {2, 8}};
std::vector<point> hull = grahamScan(points);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like a printing statment before finding hull, in order to show the points.


struct point{
float x;
float y;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use float here? I think double is OK.

@leios
Copy link
Member

leios commented Jul 7, 2019

@dovisutu No pressure on the discord, then! I just wanted to make sure you were kept in-the-loop with the latest changes, but most of that discussion is at least duplicated here on github.

Thanks for all the help!

@dovisutu
Copy link
Contributor

dovisutu commented Jul 7, 2019

@dovisutu No pressure on the discord, then! I just wanted to make sure you were kept in-the-loop with the latest changes, but most of that discussion is at least duplicated here on github.
Thanks for all the help!

BTW, I just fixed my VPN...
I'll try to join discord chat then.

@AkashDhiman
Copy link
Contributor Author

I am getting a somewhat odd runtime error, the code compiles and the output is also shown but (only sometimes) with the error:

*** Error in `./a.out': free(): invalid next size (fast): 0x00005577d36da230 ***

after which it prints a memory map which I have not shown here.
I suspect it to be a buffer overflow maybe? Can anyone give me a suggestion on how to deal with it?

@AkashDhiman
Copy link
Contributor Author

I think I fixed the runtime error, I believe that in the previous commit the runtime error was due to line 32 for loop, where the iterator could access location beyond the last element of vector.

Copy link
Contributor

@dovisutu dovisutu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's another runtime error:

debug assertion failed!
Program: ......
File: ...\xutility
Line: 629

Expression: invalid comparer

This review fixes that.

};

bool ccw(point a, point b, point c){
return ((b.x - a.x)*(c.y - a.y) >= (b.y - a.y)*(c.x - a.x));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a strict weak ordering Predication.

Suggested change
return ((b.x - a.x)*(c.y - a.y) >= (b.y - a.y)*(c.x - a.x));
return ((b.x - a.x)*(c.y - a.y) > (b.y - a.y)*(c.x - a.x));

Copy link
Contributor

@dovisutu dovisutu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least to me, the code is fine now.

Copy link
Member

@leios leios left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @dovisutu, the code looks fine, so I am happy to merge it!

@leios leios merged commit e067fcb into algorithm-archivists:master Jul 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Implementation This provides an implementation for an algorithm. (Code and maybe md files are edited.)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants