-
Notifications
You must be signed in to change notification settings - Fork 18.8k
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
Implement Smooth Sort #5236
base: master
Are you sure you want to change the base?
Implement Smooth Sort #5236
Conversation
next step is to improve it to leonardo sort
Additionaly done the following to fix pervious issues:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to derive your class from SortAlgorithm
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the answer to the above questions is yes, then if should be enough to derive the SmoothSortTest
from SortingAlgorithmTest
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it is possible, I just have to use generic T[]
in place of Integer[]
modify the code a little bit and use .compareTo()
and it should be good. I shall work on it and update this PR. I'll comment here once changes are ready.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated the code, haven't pushed it yet. The smooth sort algorithm I implemented seems to be failing for most arrays of size greater than 700. I guess the problem is with how I am calculating the left child of a node. I am having a look into it. I shall provide an update here once I am done with the fix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated to code, derived the class from SortAlgorithm, removed unnecessary return statements , renamed variables to make the code more understandable.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5236 +/- ##
============================================
+ Coverage 39.85% 40.24% +0.38%
- Complexity 2437 2470 +33
============================================
Files 517 518 +1
Lines 15471 15583 +112
Branches 2958 2981 +23
============================================
+ Hits 6166 6271 +105
- Misses 9016 9018 +2
- Partials 289 294 +5 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment the code is way too complex. I would suggest to:
- implement
LeonardoHeap
(or use one of the existing implementations inheaps
), - use it in the implementation of
SmoothSort
.
|
||
int indexOfRightChild = rootNodeIndices.get(j) - 1; // right child is of level n-2 | ||
int indexOfLeftChild = rootNodeIndices.get(j) - 1 - getLeonardoNumbers()[currentLeonardoLevel - 2]; | ||
if (array[prevRootNodeIndex].compareTo(array[indexOfRightChild]) > 0 && array[prevRootNodeIndex].compareTo(array[indexOfLeftChild]) > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I see there is no test with array[prevRootNodeIndex].compareTo(array[indexOfRightChild]) > 0
evaluating to true
and array[prevRootNodeIndex].compareTo(array[indexOfLeftChild]) > 0
to false
.
To ensure that the logic is correct, please add a missing test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I shall add a specific test case in SmoothSortTest.java
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see why this is happening and I shall try my best to explain in this comment.
Leonardo Heap has the following three properties that define it (Going through the array from left to right):
- The trees are in decreasing order of levels
- Root nodes of the trees are in increasing order
- Each tree is in a 'max-heap' state.
The Level-1 leonardo Tree(L1) and Level 0 leonardo Tree (L0) are the 'base case' trees as they have exactly one node.
At any given valid leonardo heap, if the heap contains both L1 and L0 tree then the element in L0 tree will always be greater than element at L1 tree, because of the second property mentioned above ( L0 >= L1 )
When L2 tree is being constructed, the level0 tree becomes the right child level1 tree becomes the left child. And hence it is not possible to have a condition such that level0 < prevRootNodeVal < level1 as it would be a voilation of the above.
This section of the wiki page and this article (under the imageAn erroneous swap
) mention that root needs to be bigger than the new element and the roots of its child nodes for a swap to happen. However this article(in page 6) mentions that the preRootValue should exceede its largest son.
I believe the statement in wiki is more genreic statement than a technical one and this condition can be optimized to just having array[prevRootNodeIndex].compareTo(array[indexOfLeftChild]) > 0
. I shall however look around for more articles that suggest otherwise before I make changes to this.
Integer[] leonardoNumbers = {1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 1405773, 18454929, 29860703, 48315633, 78176337, 126491971, | ||
204668309, 331160281, 535828591}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not to use LeonardoNumber
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The LeonardoNumber class is recursively calculating the Leonardo Numbers. I did not want to calculate(or re-calculate) the numbers everytime. I shall modify my code and use LeonardoNumber to store the results in an array before I start creating the heap and use the results stored in that array when needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vil02 I however think recrsivly calculating these numbers ( before or during the execution ) might not be a great idea and would just increase the execution time as it will run the same recursion stacks multiple times. If you still suggest using LeonardoNumber.java I shall go ahead and make changes as mentioned above.
int indexOfRightChild = rootNodeIndices.get(j) - 1; // right child is of level n-2 | ||
int indexOfLeftChild = rootNodeIndices.get(j) - 1 - getLeonardoNumbers()[currentLeonardoLevel - 2]; | ||
if (array[prevRootNodeIndex].compareTo(array[indexOfRightChild]) > 0 && array[prevRootNodeIndex].compareTo(array[indexOfLeftChild]) > 0) { | ||
swap(array, prevRootNodeIndex, currentRootNodeIndex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
swap(array, prevRootNodeIndex, currentRootNodeIndex); | |
SortUtils.swap(array, prevRootNodeIndex, currentRootNodeIndex); |
} | ||
} else { | ||
// swap | ||
swap(array, prevRootNodeIndex, currentRootNodeIndex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
swap(array, prevRootNodeIndex, currentRootNodeIndex); | |
SortUtils.swap(array, prevRootNodeIndex, currentRootNodeIndex); |
|
||
private static <T> void swap(T[] array, int idx, int idy) { | ||
T swap = array[idx]; | ||
array[idx] = array[idy]; | ||
array[idy] = swap; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private static <T> void swap(T[] array, int idx, int idy) { | |
T swap = array[idx]; | |
array[idx] = array[idy]; | |
array[idy] = swap; | |
} |
} | ||
|
||
if (array[childIndexForSwap].compareTo(array[currentRootNodeIndex]) > 0) { | ||
// swap(And keep on swapping I guess, I did not implement that which might be causing issue?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment was added during debugging, I shall remove this in the next commit.
// swap | ||
swap(array, prevRootNodeIndex, currentRootNodeIndex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// swap | |
swap(array, prevRootNodeIndex, currentRootNodeIndex); | |
SortUtils.swap(array, prevRootNodeIndex, currentRootNodeIndex); |
No need for the comment. The name of the method swap
is pretty clear.
leonardoTreeLevelforHeapify = currentLeonardoTreeLevels[j - 1]; | ||
} | ||
j = j - 1; | ||
if (j == i - 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
j == i - 1
is never false
(among the existing test cases).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do have a test case (not currently committed) with around 900 entries where this evalueates to false during creation of the heap. I can try to reduce the entires in such a way that the condition still evaluates to true, I will for sure end up having an array of size 20-30 ( as i will need 3 trees of non consecutive levels .... L1 L3 and L5 at least ).
Would it be fine if I added a test case in SmoothSortTest.java
with around 20-30 elements in the test? If yes, I shall work on it at the very end after resolving the other conversations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: Yes, this condition is never false. I belive what I intented to do was run maxHeapifyLeonardoTree
if you reached the left most tree and further swaps are still present.
I am checking this as well.
// maxHeapifyLeonardoTree(rightChildIndex, currentLeonardoLevel - 2, array); | ||
// maxHeapifyLeonardoTree(leftChildIndex, currentLeonardoLevel - 1, array); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This too was added for debugging, I shall remove this in my next commit. please ignore this.
if (consecutiveTreeIndices[0] != -1) { | ||
// if 0th or 1st index is -1 that implies there are no concequtive trees | ||
leonardoLevelTracker = leonardoLevelTracker & ~(1 << consecutiveTreeIndices[0]); | ||
leonardoLevelTracker = leonardoLevelTracker & ~(1 << consecutiveTreeIndices[1]); | ||
leonardoLevelTracker = leonardoLevelTracker | (1 << consecutiveTreeIndices[1] + 1); | ||
} else if ((leonardoLevelTracker & 2) == 0) { | ||
leonardoLevelTracker = leonardoLevelTracker | (1 << 1); | ||
} else { | ||
leonardoLevelTracker = leonardoLevelTracker | (1 << 0); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to apply the SingleBitOperations
(or something from bitmanipulation
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not come accross this class earlier.
Yes, this class can definately be used. I shall modify this section of the code as well.
I did try to use existing implementaions of Heaps, however Leonardo Heap is a bit different from the others since this heap contains multiple loenardo trees of very specific shapes and the root node being the right most elemnent in the list. I can crate a new class |
Adding this comment to provide updates and ensure this PR is not marked as stale: I have refactored the code, not yet pushed as I want to do some more changes and try to use the interface Heap.java |
clang-format -i --style=file path/to/your/file.java