mirror of
https://github.com/TheAlgorithms/C
synced 2024-11-22 05:21:49 +03:00
[bug+docs] add docs + fix error in getMax (#579)
* add docs + fix error in getMax * fix clang-tidy alerts and errors * rearrange comments * allow subfolders in data_structure * set pointer to NULL after purge
This commit is contained in:
parent
83a8239805
commit
296f3d00d0
2
.github/workflows/awesome_workflow.yml
vendored
2
.github/workflows/awesome_workflow.yml
vendored
@ -142,7 +142,7 @@ jobs:
|
|||||||
print(f"{len(space_files)} files contain space or dash characters:")
|
print(f"{len(space_files)} files contain space or dash characters:")
|
||||||
print("\n".join(space_files) + "\n")
|
print("\n".join(space_files) + "\n")
|
||||||
|
|
||||||
nodir_files = [file for file in cpp_files if file.count(os.sep) != 1 and "project_euler" not in file]
|
nodir_files = [file for file in cpp_files if file.count(os.sep) != 1 and "project_euler" not in file and "data_structure" not in file]
|
||||||
if nodir_files:
|
if nodir_files:
|
||||||
print(f"{len(nodir_files)} files are not in one and only one directory:")
|
print(f"{len(nodir_files)} files are not in one and only one directory:")
|
||||||
print("\n".join(nodir_files) + "\n")
|
print("\n".join(nodir_files) + "\n")
|
||||||
|
@ -1,29 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief A basic unbalanced binary search tree implementation in C.
|
||||||
|
* @details The implementation has the following functionalities implemented:
|
||||||
|
* - Insertion
|
||||||
|
* - Deletion
|
||||||
|
* - Search by key value
|
||||||
|
* - Listing of node keys in order of value (from left to right)
|
||||||
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
/* A basic unbalanced binary search tree implementation in C, with the following
|
/** Node, the basic data structure in the tree */
|
||||||
functionalities implemented:
|
|
||||||
- Insertion
|
|
||||||
- Deletion
|
|
||||||
- Search by key value
|
|
||||||
- Listing of node keys in order of value (from left to right)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Node, the basic data structure in the tree
|
|
||||||
typedef struct node
|
typedef struct node
|
||||||
{
|
{
|
||||||
// left child
|
struct node *left; /**< left child */
|
||||||
struct node *left;
|
struct node *right; /**< right child */
|
||||||
|
int data; /**< data of the node */
|
||||||
// right child
|
|
||||||
struct node *right;
|
|
||||||
|
|
||||||
// data of the node
|
|
||||||
int data;
|
|
||||||
} node;
|
} node;
|
||||||
|
|
||||||
// The node constructor, which receives the key value input and returns a node
|
/** The node constructor, which receives the key value input and returns a node
|
||||||
// pointer
|
* pointer
|
||||||
|
* @param data data to store in a new node
|
||||||
|
* @returns new node with the provided data
|
||||||
|
* @note the node must be deleted before program terminates to avoid memory
|
||||||
|
* leaks
|
||||||
|
*/
|
||||||
node *newNode(int data)
|
node *newNode(int data)
|
||||||
{
|
{
|
||||||
// creates a slug
|
// creates a slug
|
||||||
@ -37,61 +38,82 @@ node *newNode(int data)
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insertion procedure, which inserts the input key in a new node in the tree
|
/** Insertion procedure, which inserts the input key in a new node in the tree
|
||||||
|
* @param root pointer to parent node
|
||||||
|
* @param data value to store int he new node
|
||||||
|
* @returns pointer to parent node
|
||||||
|
*/
|
||||||
node *insert(node *root, int data)
|
node *insert(node *root, int data)
|
||||||
{
|
{
|
||||||
// If the root of the subtree is null, insert key here
|
// If the root of the subtree is null, insert key here
|
||||||
if (root == NULL)
|
if (root == NULL)
|
||||||
|
{
|
||||||
root = newNode(data);
|
root = newNode(data);
|
||||||
// If it isn't null and the input key is greater than the root key, insert
|
}
|
||||||
// in the right leaf
|
|
||||||
else if (data > root->data)
|
else if (data > root->data)
|
||||||
|
{
|
||||||
|
// If it isn't null and the input key is greater than the root key,
|
||||||
|
// insert in the right leaf
|
||||||
root->right = insert(root->right, data);
|
root->right = insert(root->right, data);
|
||||||
// If it isn't null and the input key is lower than the root key, insert in
|
}
|
||||||
// the left leaf
|
|
||||||
else if (data < root->data)
|
else if (data < root->data)
|
||||||
|
{ // If it isn't null and the input key is lower than the root key, insert
|
||||||
|
// in the left leaf
|
||||||
root->left = insert(root->left, data);
|
root->left = insert(root->left, data);
|
||||||
|
}
|
||||||
// Returns the modified tree
|
// Returns the modified tree
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utilitary procedure to find the greatest key in the left subtree
|
/** Utilitary procedure to find the greatest key in the left subtree
|
||||||
|
* @param root pointer to parent node
|
||||||
|
* @returns pointer to parent node
|
||||||
|
*/
|
||||||
node *getMax(node *root)
|
node *getMax(node *root)
|
||||||
{
|
{
|
||||||
// If there's no leaf to the right, then this is the maximum key value
|
// If there's no leaf to the right, then this is the maximum key value
|
||||||
if (root->right == NULL)
|
if (root->right != NULL)
|
||||||
|
{
|
||||||
|
return getMax(root->right);
|
||||||
|
}
|
||||||
return root;
|
return root;
|
||||||
else
|
|
||||||
root->right = getMax(root->right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletion procedure, which searches for the input key in the tree and removes
|
/** Deletion procedure, which searches for the input key in the tree and removes
|
||||||
// it if present
|
* it if present
|
||||||
|
* @param root pointer to parent node
|
||||||
|
* @param data value to search for int the node
|
||||||
|
* @returns pointer to parent node
|
||||||
|
*/
|
||||||
node *delete (node *root, int data)
|
node *delete (node *root, int data)
|
||||||
{
|
{
|
||||||
// If the root is null, nothing to be done
|
// If the root is null, nothing to be done
|
||||||
if (root == NULL)
|
if (root == NULL)
|
||||||
|
{
|
||||||
return root;
|
return root;
|
||||||
// If the input key is greater than the root's, search in the right subtree
|
}
|
||||||
else if (data > root->data)
|
else if (data > root->data)
|
||||||
|
{ // If the input key is greater than the root's, search in the right
|
||||||
|
// subtree
|
||||||
root->right = delete (root->right, data);
|
root->right = delete (root->right, data);
|
||||||
// If the input key is lower than the root's, search in the left subtree
|
}
|
||||||
else if (data < root->data)
|
else if (data < root->data)
|
||||||
|
{ // If the input key is lower than the root's, search in the left subtree
|
||||||
root->left = delete (root->left, data);
|
root->left = delete (root->left, data);
|
||||||
// If the input key matches the root's, check the following cases
|
}
|
||||||
// termination condition
|
|
||||||
else if (data == root->data)
|
else if (data == root->data)
|
||||||
{
|
{
|
||||||
// Case 1: the root has no leaves, remove the node
|
// If the input key matches the root's, check the following cases
|
||||||
|
// termination condition
|
||||||
if ((root->left == NULL) && (root->right == NULL))
|
if ((root->left == NULL) && (root->right == NULL))
|
||||||
{
|
{ // Case 1: the root has no leaves, remove the node
|
||||||
free(root);
|
free(root);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// Case 2: the root has one leaf, make the leaf the new root and remove
|
|
||||||
// the old root
|
|
||||||
else if (root->left == NULL)
|
else if (root->left == NULL)
|
||||||
{
|
{ // Case 2: the root has one leaf, make the leaf the new root and
|
||||||
|
// remove
|
||||||
|
// the old root
|
||||||
node *tmp = root;
|
node *tmp = root;
|
||||||
root = root->right;
|
root = root->right;
|
||||||
free(tmp);
|
free(tmp);
|
||||||
@ -104,10 +126,10 @@ node *delete (node *root, int data)
|
|||||||
free(tmp);
|
free(tmp);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
// Case 3: the root has 2 leaves, find the greatest key in the left
|
|
||||||
// subtree and switch with the root's
|
|
||||||
else
|
else
|
||||||
{
|
{ // Case 3: the root has 2 leaves, find the greatest key in the left
|
||||||
|
// subtree and switch with the root's
|
||||||
|
|
||||||
// finds the biggest node in the left branch.
|
// finds the biggest node in the left branch.
|
||||||
node *tmp = getMax(root->left);
|
node *tmp = getMax(root->left);
|
||||||
|
|
||||||
@ -120,30 +142,55 @@ node *delete (node *root, int data)
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search procedure, which looks for the input key in the tree and returns 1 if
|
/** Search procedure, which looks for the input key in the tree and returns 1 if
|
||||||
// it's present or 0 if it's not in the tree
|
* it's present or 0 if it's not in the tree
|
||||||
|
* @param root pointer to parent node
|
||||||
|
* @param data value to store int he new node
|
||||||
|
* @returns 0 if value not found in the nodes
|
||||||
|
* @returns 1 if value was found
|
||||||
|
*/
|
||||||
int find(node *root, int data)
|
int find(node *root, int data)
|
||||||
{
|
{
|
||||||
// If the root is null, the key's not present
|
// If the root is null, the key's not present
|
||||||
if (root == NULL)
|
if (root == NULL)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
// If the input key is greater than the root's, search in the right subtree
|
}
|
||||||
else if (data > root->data)
|
else if (data > root->data)
|
||||||
|
{
|
||||||
|
// If the input key is greater than the root's, search in the right
|
||||||
|
// subtree
|
||||||
return find(root->right, data);
|
return find(root->right, data);
|
||||||
// If the input key is lower than the root's, search in the left subtree
|
}
|
||||||
else if (data < root->data)
|
else if (data < root->data)
|
||||||
|
{
|
||||||
|
// If the input key is lower than the root's, search in the left subtree
|
||||||
return find(root->left, data);
|
return find(root->left, data);
|
||||||
// If the input and the root key match, return 1
|
}
|
||||||
else if (data == root->data)
|
else if (data == root->data)
|
||||||
|
{
|
||||||
|
// If the input and the root key match, return 1
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{ // unknown result!!
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Utilitary procedure to measure the height of the binary tree
|
/** Utilitary procedure to measure the height of the binary tree
|
||||||
|
* @param root pointer to parent node
|
||||||
|
* @param data value to store int he new node
|
||||||
|
* @returns 0 if value not found in the nodes
|
||||||
|
* @returns height of nodes to get to data from parent node
|
||||||
|
*/
|
||||||
int height(node *root)
|
int height(node *root)
|
||||||
{
|
{
|
||||||
// If the root is null, this is the bottom of the tree (height 0)
|
// If the root is null, this is the bottom of the tree (height 0)
|
||||||
if (root == NULL)
|
if (root == NULL)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Get the height from both left and right subtrees to check which is
|
// Get the height from both left and right subtrees to check which is
|
||||||
@ -154,27 +201,40 @@ int height(node *root)
|
|||||||
// The final height is the height of the greatest subtree(left or right)
|
// The final height is the height of the greatest subtree(left or right)
|
||||||
// plus 1(which is the root's level)
|
// plus 1(which is the root's level)
|
||||||
if (right_h > left_h)
|
if (right_h > left_h)
|
||||||
|
{
|
||||||
return (right_h + 1);
|
return (right_h + 1);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return (left_h + 1);
|
return (left_h + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Utilitary procedure to free all nodes in a tree
|
/** Utilitary procedure to free all nodes in a tree
|
||||||
|
* @param root pointer to parent node
|
||||||
|
*/
|
||||||
void purge(node *root)
|
void purge(node *root)
|
||||||
{
|
{
|
||||||
if (root != NULL)
|
if (root != NULL)
|
||||||
{
|
{
|
||||||
if (root->left != NULL)
|
if (root->left != NULL)
|
||||||
|
{
|
||||||
purge(root->left);
|
purge(root->left);
|
||||||
|
}
|
||||||
if (root->right != NULL)
|
if (root->right != NULL)
|
||||||
|
{
|
||||||
purge(root->right);
|
purge(root->right);
|
||||||
|
}
|
||||||
free(root);
|
free(root);
|
||||||
|
root = NULL; // reset pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traversal procedure to list the current keys in the tree in order of value
|
/** Traversal procedure to list the current keys in the tree in order of value
|
||||||
// (from the left to the right)
|
* (from the left to the right)
|
||||||
|
* @param root pointer to parent node
|
||||||
|
*/
|
||||||
void inOrder(node *root)
|
void inOrder(node *root)
|
||||||
{
|
{
|
||||||
if (root != NULL)
|
if (root != NULL)
|
||||||
@ -185,7 +245,8 @@ void inOrder(node *root)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
/** Main funcion */
|
||||||
|
int main()
|
||||||
{
|
{
|
||||||
// this reference don't change.
|
// this reference don't change.
|
||||||
// only the tree changes.
|
// only the tree changes.
|
||||||
@ -218,7 +279,9 @@ void main()
|
|||||||
root = delete (root, data);
|
root = delete (root, data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
printf("Tree is already empty!\n");
|
printf("Tree is already empty!\n");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
@ -240,4 +303,6 @@ void main()
|
|||||||
|
|
||||||
// deletes the tree from the heap.
|
// deletes the tree from the heap.
|
||||||
purge(root);
|
purge(root);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user