#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/***********************************************************
This program implements a simple priority queue using a heap.
The items being sorted are records, where each record contains a last name, a
first name, and an ID number. The records will be sorted according
to their ID numbers, from smallest to largest.
A heap (in this context) is a binary tree with the following
properties:
- The value at a parent node is greater than the value at
either child node.
- The heap is implemented using an array. Each element of the
array is a pointer to a record.
- For a parent node at index i of the array, the children are
found at indices (i*2)+1 and (i*2)+2. All parent nodes
have two children, except for the very last parent node.
- For a child node at index i of the array, the parent is
found at index (x-1)/2 (using integer division).
************************************************************/
// This is the declaration of the RECORD type
typedef struct {
char *last_name;
char *first_name;
long id_number;
} RECORD;
RECORD *read_record();
/* This function reads in the data for a single record from the
standard input by calling scanf. If scanf succeeds in
reading the data, a new RECORD is allocated, populated
with the data, and a pointer to the record is returned
*/
RECORD *read_record()
{
char lastname[100], firstname[100];
RECORD *p;
long id;
int res = scanf("%s %s %ld", lastname, firstname, &id);
if (res == EOF) // EOF is -1
return NULL;
p = malloc(sizeof(RECORD));
p->last_name = malloc(strlen(lastname)+1);
strcpy(p->last_name, lastname);
p->first_name = malloc(strlen(lastname)+1);
strcpy(p->first_name, firstname);
p->id_number = id;
return p;
}
/*
These are macros that are convenient for finding the parent,
left child, and right child of a node at index x of the array.
*/
#define PARENT(x) ((x-1)>>1)
#define LEFT(x) ((x<<1)+1)
#define RIGHT(x) ((x<<1)+2)
// This is the fixed size of the heap array.
#define SIZE 500
// The heap is an array of pointers to records
RECORD *heap[SIZE];
// This is a count of the number of nodes in the head.
// It is also the index of the next available slot in the
// array.
// int heap_count = 0;
extern int heap_count; // in assembly
void heap_swap(int i, int j);
/*
This function simply swaps the contents of the heap
array at indices i and j. The contents of each
element of the array is just a pointer to a record.
*/
void heap_swap(int i, int j) {
RECORD *temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
void sift_up(int i);
/*
This is the heap "sift up" function. It starts with a leaf, at array index i, that has just
been added to the tree and might violate the heap requirement (i.e. the value of the leaf
may be less than that of its parent). It works by comparing the node at index i to
its parent. If the value of the node is not less than its parent, the heap property
has been maintained and the function can return. Otherwise, the values at the node and at its
parent are swapped, i is set to the index of the parent node (since the value at the parent now
may be less than at the grandparent), and the process iterates until either the heap property
is satisfied or the root (at index 0) is reached.
*/
void sift_up(int i)
{
while (i != 0) {
if (heap[i]->id_number >= heap[PARENT(i)]->id_number) // correct situation, no need to continue
return;
// otherwise, need to swap with parent
heap_swap(i, PARENT(i));
i = PARENT(i);
}
}
void sift_down();
/*
This function performs the heap "sift down" process, which occurs when
a new value has been inserted at the root of the tree (i.e. when the
existing root is removed and the last leaf in the tree is inserted at
the root). Starting at the root as the parent node, the values of the
two child nodes are compared to each other. Then if the value at the
parent is greater than the value at the smaller child, the values at
the parent and the smaller child are swapped, and the process
continues with the smaller child being considered the parent in the
next iteration. The process terminates when a leaf is reached.
At any point, if the value at the parent is not greater than the
smaller child, the heap property has been preserved and the function
can return. If a parent ony has one child (which must be the left
child), then the left child is considered the smaller child.
*/
void sift_down()
{
int i = 0;
int last_parent = PARENT(heap_count - 1);
int min_child;
while (i <= last_parent) {
if ((RIGHT(i) >= heap_count) ||
(heap[LEFT(i)]->id_number <= heap[RIGHT(i)]->id_number))
min_child = LEFT(i);
else
min_child = RIGHT(i);
if (heap[i]->id_number > heap[min_child]->id_number) {
heap_swap(i, min_child);
i = min_child;
}
else // done sifting down
return;
}
}
void heap_insert(RECORD *p);
/*
This function inserts a new record into the
heap. It does so by adding a pointer to the
record at index heap_count (the first open
slot) in the array and then calling
sift_up(), above, to restore the heap property.
*/
void heap_insert(RECORD *p)
{
if (heap_count >= SIZE) {
printf("Error: Heap is full\n");
exit(1);
}
heap[heap_count] = p;
sift_up(heap_count);
heap_count++;
}
RECORD *heap_remove();
/*
This function removes the smallest value in the heap, i.e.
the value at the root node (at array index 0), and returns
that smallest value (which is a pointer to a record).
Before returning, it writes the value of the last
leaf (at index heap_count-1 of the array) into to the
root node and then calls sift_down(), above, to
restore the heap property.
*/
RECORD *heap_remove()
{
if (heap_count <= 0) {
printf("Error: Heap is empty\n");
exit(1);
}
RECORD *result = heap[0];
heap_count--;
heap[0] = heap[heap_count];
sift_down();
return result;
}
/*
This is the main function, which repeatedly calls read_record and
heap_insert to insert pointers to records into the heap. Once
all the data has been read, it repeatedly calls heap_remove()
to print out the records in sorted order, according the ID number
*/
int main() {
RECORD *temp = malloc(sizeof(RECORD));
printf("sizeof(CELL) = %ld\n", sizeof(RECORD));
printf("Offset of lastname = %ld\n", (void *) &(temp->last_name) - (void *) temp);
printf("Offset of firstname = %ld\n", (void *) &(temp->first_name) - (void *) temp);
printf("Offset of idnumber = %ld\n", (void *) &(temp->id_number) - (void *) temp);
RECORD *p = NULL;
p = read_record();
while (p != NULL) {
heap_insert(p);
p = read_record();
}
printf("Sorted\n------\n");
while (heap_count != 0) {
p = heap_remove();
printf("%ld: %s, %s\n", p->id_number, p->last_name, p->first_name);
}
}
Write, Run & Share C Language code online using OneCompiler's C online compiler for free. It's one of the robust, feature-rich online compilers for C language, running the latest C version which is C18. Getting started with the OneCompiler's C editor is really simple and pretty fast. The editor shows sample boilerplate code when you choose language as 'C' and start coding!
OneCompiler's C online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample C program which takes name as input and print your name with hello.
#include <stdio.h>
int main()
{
char name[50];
printf("Enter name:");
scanf("%s", name);
printf("Hello %s \n" , name );
return 0;
}
C language is one of the most popular general-purpose programming language developed by Dennis Ritchie at Bell laboratories for UNIX operating system. The initial release of C Language was in the year 1972. Most of the desktop operating systems are written in C Language.
When ever you want to perform a set of operations based on a condition if-else is used.
if(conditional-expression) {
// code
} else {
// code
}
You can also use if-else for nested Ifs and if-else-if ladder when multiple conditions are to be performed on a single variable.
Switch is an alternative to if-else-if ladder.
switch(conditional-expression) {
case value1:
// code
break; // optional
case value2:
// code
break; // optional
...
default:
// code to be executed when all the above cases are not matched;
}
For loop is used to iterate a set of statements based on a condition.
for(Initialization; Condition; Increment/decrement){
// code
}
While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.
while(condition) {
// code
}
Do-while is also used to iterate a set of statements based on a condition. It is mostly used when you need to execute the statements atleast once.
do {
// code
} while (condition);
Array is a collection of similar data which is stored in continuous memory addresses. Array values can be fetched using index. Index starts from 0 to size-1.
data-type array-name[size];
data-type array-name[size][size];
Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increases re-usuability and modularity.
Two types of functions are present in C
Library functions are the in-built functions which are declared in header files like printf(),scanf(),puts(),gets() etc.,
User defined functions are the ones which are written by the programmer based on the requirement.
return_type function_name(parameters);
function_name (parameters)
return_type function_name(parameters) {
//code
}