forked from rambli/heapsort
/
heapsort.c
252 lines (229 loc) · 7.19 KB
/
heapsort.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/**
* @file heapsort.c
* @brief Heapsort implementation
* @author Rohan Ambli
*/
#include "heapsort.h"
//#define HEAPSORT
/*!*****************************************************************
* \fn add_node(node **root, int data, node *parent)
* \brief - Create and add a new node to the passed in root, which
* is recursively traversed to find the right place where
* the new node can be inserted. If (data < root->data),
* then it is inserted to the left, else to the right.
* Once inserted, the tree is normalized. (normalize_tree)
* \param root - root node
* \param data - new data to be added
* \param parent - parent for the new node
* \return void
* \note FUNCTION IS RECURSIVE
*******************************************************************/
void add_node(node **root, int data, node *parent)
{
if (NULL != *root)
{
parent = *root;
add_node(&((*root)->link[DIR(data,(*root)->data)]), data, parent);
}
else
{
*root = create_node(data, parent);
#ifdef HEAPSORT
/* Created node, re-arrange it in the tree such that it is
smaller than its parent. If normalizing, then tree is used
used in heapsort. If normalizing is skipped, it is a regular
binary tree. */
normalize_tree(*root);
#endif /* HEAPSORT */
}
}
/*!***************************************************************************
\fn normalize_tree(node *norm_node)
\brief - The passed in node is tested against its parent, and swapped if it is smaller
than the parent. This is done recursively until the condition is satisfied.
\param norm_node - node to be normalized
\return void
*****************************************************************************/
void normalize_tree(node *norm_node)
{
if(NULL == norm_node)
return;
PRINT("Normalizing tree with node %d\n", norm_node->data);
if(NULL == norm_node)
{
PRINT("Did not find node %d\n", norm_node->data);
return;
}
node *parent = get_parent(norm_node);
if(NULL == parent)
PRINT("node %d does not have a parent. This is the root\n", norm_node->data);
while(NULL != parent)
{
if(norm_node->data < parent->data)
{
/* Child data is smaller than parent, swap */
swap(norm_node, parent);
PRINT("Swapped child(%p):%d parent(%p):%d\n", norm_node, norm_node->data, parent, parent->data);
}
else
{
PRINT("Child is %d, parent is %d.. already normalized\n", norm_node->data, parent->data);
/* If this <child,parent> pair is normalized, all pairs above here are normalized as well,
return here */
break;
}
/* Go up a level to see if our child (now parent after swap) needs to climb higher if it is
smaller than its new parent. */
norm_node = parent;
parent = get_parent(norm_node);
}
return;
}
/*!***************************************************************************
\fn normalize_tree_root(node *root)
\brief - During sorting, the largest child is brought up to the root
as the root being the smallest is extracted. The tree needs to
be normalized top-down so the the next smallest node floats to
the top. This is in a way reverse of normalize_tree() where a
node is added to the bottom and checked if it needs to be sent up
top. Here we add a node to the top and check if it needs to be
sent lower in the tree.
\param node* - tree root
\return void
*****************************************************************************/
void normalize_tree_root(node *root)
{
node *sc = NULL;
while(NULL != root)
{
PRINT("Normalizing tree with root %d\n", root->data);
sc = get_smaller_child(root);
if(sc)
{
/* Smallest child of this node is smaller than this node.
Swap them and continue checking until this we reach the bottom */
if(sc->data < root->data)
{
swap(sc, root);
}
}
/* Now child becomes root, and same check continues lower */
root = sc;
}
return;
}
/*!***************************************************************************
\fn sort(node **root)
\brief - The sorting function
\param **root - tree root
\return - void
*****************************************************************************/
void sort(node **root)
{
int i = 10;
node *lc = NULL;
while(NULL != *root)
{
/* Get last node which is one of the largest nodes (definitely larger than our current root)
and make it the root of the tree. Then normalize tree so the next smallest number can
float to the top */
lc = get_last_child(*root);
/* Reached the root, last element */
if(lc == *root)
{
printf("Extracting %d\n Done sorting!!\n", lc->data);
free(*root);
lc = *root = NULL;
}
if(lc)
{
int data = lc->data;
/* Extract the current root which is the smallest number currently */
printf("Extracting %d\n", (*root)->data);
/* Set root to the larger child, which is brought up from below */
(*root)->data = data;
/* Free the child's old node as it is now at the root position. Make sure we
set it's parent's link to it to NULL.
Don't really need to check if its parent is NULL or not (its not as its not
the tree root), but we do it for sanity check. */
if(NULL != lc->parent)
{
if(NULL != lc->parent->link[LEFT])
if(lc->parent->link[LEFT]->data == lc->data)
lc->parent->link[LEFT] = NULL;
if(NULL != lc->parent->link[RIGHT])
if(lc->parent->link[RIGHT]->data == lc->data)
lc->parent->link[RIGHT] = NULL;
}
/* Parent link to this is now NULL, free it */
free(lc);
lc = NULL;
/* The child which is one of the largest nodes in this tree is sitting at the
root, normalize tree so that it sinks to the bottom and next smallest node
floats to the top */
normalize_tree_root(*root);
}
}
}
/*!***************************************************************************
\fn balance_tree(node **root)
\brief - Called when the tree is unbalanced, to, well... balance it.
\param **root - tree root
\return - void
*****************************************************************************/
void balance_tree(node **root)
{
int height = find_tree_balance(*root);
/* If balance goes over 2, rebalance the tree */
if(2 < abs(height))
{
node *oldroot = *root;
(height > 0) ? rotate_tree_left(root):rotate_tree_right(root);
height = find_tree_balance(*root);
PRINT("Old root: %d New root: %d(%p) height is %d\n",
oldroot->data, (*root)->data, *root, height);
}
}
/*!*************************************************************************
\fn main
\brief - main fn to perform heapsort
****************************************************************************/
int main(void)
{
node *root = NULL;
int i = 0;
int scan = 0;
#if 0
int arr[] = {5,10,7,4,15,25,13};
for(i = 0; i < 7; i++)
{
add_node(&root, arr[i], root);
#ifndef HEAPSORT
balance_tree(&root);
#endif /* !HEAPSORT */
}
PRINT("============ BEGIN SORTING============\n");
#else
while(1)
{
printf("Enter number:\n");
scanf("%d", &scan);
if(scan == (int)-100)
break;
else
{
add_node(&root, scan, root);
#ifndef HEAPSORT
balance_tree(&root);
#endif /* !HEAPSORT */
}
}
#endif
print_tree(root);
printf("\n");
#ifdef HEAPSORT
sort(&root);
#endif /* HEAPSORT */
free_tree(root);
return 0;
}