You are on page 1of 13

Theory:

9. Structures in C

a. struct type variables description / declaration

A structure variable can either be declared with structure declaration or as a separate


declaration like basic types.
// A variable declaration with structure declaration.

struct Point

int x, y;

} p1; // The variable p1 is declared with 'Point'

Or

// A variable declaration like basic data types

struct Point

int x, y;

};

int main()

struct Point p1; // The variable p1 is declared like a normal


variable

Note: In C++, the struct keyword is optional before in declaration of a variable. In C, it is


mandatory.

Structure members cannot be initialized with declaration. For example the following C
program fails in compilation.
struct Point

int x = 0; // COMPILER ERROR: cannot initialize members here

int y = 0; // COMPILER ERROR: cannot initialize members here

};

The reason for above error is simple, when a datatype is declared, no


memory is allocated for it. Memory is allocated only when variables are
created.
b. Arrays of structures

Like other primitive data types, we can create an array of structures.

An array of structres in C can be defined as the collection of multiple structures variables


where each variable contains information about different entities. The array
of structures in C are used to store information about multiple entities of different data
types. The array of structures is also known as the collection of structures.

struct Point
{
   int x, y;
};
  
int main()
{
   // Create an array of structures
   struct Point arr[10];
}

c. Accessing structure fields

Structure members are accessed using dot (.) operator.

struct Point
{
   int x, y;
};
  
int main()
{
   struct Point P1;

P1.x=20; //Accessing member x of point P1


P1.y=30; //Accessing member y of point P1
}

d. Use in dynamically allocated lists

Like primitive types, we can have pointer to a structure. If we have a pointer to


structure, members are accessed using arrow ( -> ) operator.
struct Point
{
   int x, y;
};
  
int main()
{
   struct Point p1 = {1, 2};
  
   // p2 is a pointer to structure p1
   struct Point *p2 = &p1;
  
   // Accessing structure members using structure pointer
   printf("%d %d", p2->x, p2->y);
   return 0;
}

A linked list is an ordered collection of nodes, each of which contains some data,
connected using pointers. Each node is actually a struct variable, which contains an ID,
the additional data of the object and a pointer variable that points to the next node. For
example, the next structure is defined for a list of cars in a car lot.
struct carType
{
int vehicleID;
char make[20];
char model[20];
int year;
int mileage;
double cost;
Car *next; // ptr to next car in list
};
See more on point 12.

10. Dynamic memory allocation in C. Linear data structures: queue

a. Properties of the data structure – queue

Queue is a FIFO (First-In, First-Out) list, a list-like structure that provides restricted
access to its elements: elements may only be inserted at the back and removed from the
front. Similarly to stacks, queues are less flexible than lists.

b. The structure of the queue elements

Enqueue: insert elements into queue at the back.

Dequeue: remove elements from the front.

Out <- |First element||Queue| |Last element| <- In

c. operations on queue

Last (new)
First
element
element

Insertion in the empty-queue:

1. Allocate a new node and hold the pointer to it in a variable. Return from the insert
function now signaling an error if the new node cannot be allocated.

2. Store the information in the newly created node.

3. Make the newly created node point to null.

4. Make rear and front point to the newly created node.

Insertion in the non-empty queue:

1. Allocate a new node and hold the pointer to it in a variable. Return from the insert
function now signaling an error if the new node cannot be allocated.
2. Store the information in the newly created node.
3. Make the newly created node point to null.
4. Make the old rear node point the newly created node.
5. Make rear point to the newly created node.

Full and Empty Operations:

Checking for an empty queue checks to see if either the front or the rear points to null.
Checking for a full queue should always return false.
Delete an element:

1. If the queue is empty, return a flag indicating that removal could not be performed.

2. Save the pointer to the current front node.

3. Make front point to the next node.

4. If the queue is now empty, the rear must be set to null.

5. Save the information in the old front node.

6. Free the old front node.

7. Return the information that was in the front node.

d. Examples of use in algorithms (Lee algorithm)

The Lee algorithm is one possible solution for maze routing problems. It always gives an
optimal solution, if one exists, but is slow and requires large memory for dense layout.

Understanding how it works

The algorithm is a breadth-first based algorithm that uses queues to store the steps. It


usually uses the following steps:

1. Choose a starting point and add it to the queue.

2. Add the valid neighboring cells to the queue.

3. Remove the position you are on from the queue and continue to the next element.

4. Repeat steps 2 and 3 until the queue is empty.

One key concept to understand is that breadth-first searches go wide, while depth-


first searches go deep.

Using the example of a maze solving algorithm, a depth-first approach will try every
possible path one by one until it either reaches a dead end or the finish and returns the
result. However, the path it returns might not be the most efficient, but simply the first
complete path to the finish that the algorithm was able to find.

A breadth-first search will instead go out to each open space adjacent to the starting
point, then look for other possible open spaces. It will keep doing this, going out layer by
layer and trying each possible path in tandem, until it finds the finish point. Since you're
trying each path at the same time, you can be sure that the first complete path from
start to finish is also the shortest.

C++ has the queue already implemented in the <queue> library, but if you are using
something else you are welcome to implement your own version of queue.
C++ code:

int dl[] = {-1, 0, 1, 0}; // these arrays will help you travel in the 4 directions more easily
int dc[] = {0, 1, 0, -1};

queue<int> X, Y; // the queues used to get the positions in the matrix

X.push(start_x); //initialize the queues with the start position


Y.push(start_y);

void lee()
{
int x, y, xx, yy;
while(!X.empty()) // while there are still positions in the queue
{
x = X.front(); // set the current position
y = Y.front();
for(int i = 0; i < 4; i++)
{
xx = x + dl[i]; // travel in an adiacent cell from the current position
yy = y + dc[i];
if('position is valid') //here you should insert whatever conditions should apply for
your position (xx, yy)
{
X.push(xx); // add the position to the queue
Y.push(yy);
mat[xx][yy] = -1; // you usually mark that you have been to this position in the
matrix
}

X.pop(); // eliminate the first position, as you have no more use for it
Y.pop();
}
}
11. Dynamic memory allocation in C. Linear data structures: stack

a. Properties of the stack data structure

Stack is a LIFO (Last-In, First-Out) list, a list-like structure in which elements may be
inserted or removed from only one end (last-in, first-out). Stacks are less flexible than
lists, but are easier to implement, and more efficient (for those operations they can do).

Given a stack, the accessible element of the stack is called the top element.

Elements are not said to be inserted; they are pushed onto the stack.

When an element (the last one) is removed, an element is said to be popped from the
stack.

b. Stack structure

c. Stack operations

 push() − Pushing (storing) an element on the stack.


o Step 1 – Create a new node, pointing to null.
o Step 2 – Point the new node to the top node of the stack
o Step 3 – Actualize the top node to be the new node.
 pop() − Removing (accessing) an element from the stack.
o Step 1 − Checks if the stack is empty.
o Step 2 − If the stack is empty, produces an error and exit.
o Step 3 − If the stack is not empty, accesses the data element at which top is
pointing.
o Step 4 – Point a variable I to the node and actualize the Top to point to the
previous node.
o Step 5 – Point the *next pointer of node I to null and delete node I from the
memory.
 peek() − get the top data element of the stack, without removing it.
 isFull() − check if stack is full.
 isEmpty() − check if stack is empty.

d. Examples of use in algorithms (addition of long numbers)

Given two numbers N1 and N2 represented by two stacks, such that their most
significant digits are present at the bottom of the stack, the task is to calculate and
return the sum of the two numbers in the form of a stack.

1. Create a new stack, res to store the sum of the two stacks.

2. Initialize variables rem and sum to store the carry generated and the sum of top
elements respectively.

3. Keep popping the top elements of both the stacks and push the sum % 10 to res and
update rem as sum/10.

4. Repeat the above step until the stacks are empty. If rem is greater than 0,
insert rem into the stack.

5. Reverse the res stack so that the most significant digit present at the bottom of
the res stack.

Example:

Input:  N1={5, 8, 7, 4}, N2={2, 1, 3} 


Output:  {6, 0, 8, 7}
Explanation:
Step 1: Popped element from N1(=  4) +   Popped element from N2(= 3) = {7} and rem=0.
Step 2: Popped element from N1(= 7) +   Popped element from N2(= 1) = {7, 8} and
rem=0.
Step 3: Popped element from N1(= 8) +   Popped element from N2(= 2) = {7, 8, 0} and
rem=1.
Step 4: Popped element from N1(= 5) = {7, 8, 0, 6}
On reverse the stack, the desired arrangement {6,0,8,7} is obtained.

Input: N1={6,4,9,5,7}, N2={213} 


Output:{6, 5, 0, 0, 5}

12. Dynamic memory allocation in C. Linear data structures: lists

a. The structure of dynamically allocated lists

A linked list is an ordered collection of nodes, each of which contains some data,
connected using pointers.

Each node points to the next node in the list.

The first node in the list is called the head.

The last node in the list is called the tail.


A linked list can only be accessed sequentially. To find the 5th element, for instance, you
must start from the head and follow the links through four other nodes.

b. List properties, list types

Ordered List:

 Every node has an ID. When adding a new node in the list, we need to find firstly the
idea of the next node from the one we want to add and do the operation. This way
the list remains ordered.
 When deleting the node, you search it by it’s ID and then extract it from the least,
before destroying it, otherwise you may lose half of the list.

Unordered List:

 Doesn’t differ any much from what a queue or a stack is. The nodes are added either
to the front or to the back of the list.
 When deleted, you can either erase the first node, the last one or find the one with
the information you want to delete from the list, extract it and erase it from the
memory.

Properties:

Each element in the list points to the next element. That’s how they hold together.
Imagine a bunch of children, which have names and are holding with the left hand the
right shoulder of the next child. The information are their names, the pointer to the next
child are their left hand. If you break one of the connections, you lose al the nodes (kids)
after the broken connection. For example, if you have the list “ABCDEFG” and you break
the connection between “C” and “D”, you lose the sublist “DEFG”.

c. List operations

Adding a node between 2 nodes:

 Step 1: Create the new node, pointing to null, and insert the information in it.
 Step 2: Find in the list the node A before which you want to add the new node, and
the node B, which is after A. Generate an error if you don’t find the points.
 Step 3: Point the *next pointer of your new node to B.
 Step 4: Point the *next pointer of A to your new node.
Adding a node at the top of the list:

 Step 1: Create the new node, pointing to null, and insert the information in it.
 Step 2: Point the *next pointer of your new node to the top node.
 Step 3: Actualize the top node, which is your new variable.
Adding a node at the bottom of the list:
 Step 1: Create the new node, pointing to null, and insert the information in it.
 Step 2: Find the bottom node, knowing that it’s pointer *next points to null.
 Step 3: Point the *next pointer of the bottom node to your new node.
Erasing a node between 2 nodes:

 Step 1: Find in the list the node before the one with the information you want to
erase. If you can’t find it, generate an error message.
 Step 2: Point the *next pointer of the node to the *next pointer of the next node of
the one you want to delete.
 Step 3: Point the *next pointer of the node you want to delete to null.
 Step 4: Erase the node from the memory.

Deleting a node at the top of the list:

 Step 1: Actualize the TOP node, which is the next node of the one you want to
delete.
 Step 2: Point the *next pointer of the node you want to delete to null. Erase the
node from memory.
Deleting a node at the bottom of the list:
 Step 1: Find the bottom node, knowing that it’s pointer *next points to null.
 Step 2: Point the *next pointer of the previous node to null. Erase your node from
the memory.

d. Examples of use in algorithms (searching in unordered strings)

Couldn’t find anything on the internet. But, the operation is simple. Read the elements
of the string, transform them to nodes and add to the list in ordered form (only if the
order of the character in the string does not actually matter, otherwise, just add the
nodes to the top), search through the list by ID and that’s all.

Practice:

15. Describe the operation of conversion from string to integer

int stringTointeger(string str)

{
    int temp = 0;
    for (int i = 0; i < str.length(); i++) {
  
        // Since ASCII value of character from '0'
        // to '9' are contiguous. So if we subtract
        // '0' from ASCII value of a digit, we get 
        // the integer value of the digit.
temp = temp * 10 + (str[i] - '0');
// ASCII of number x – ASCII of 0 = number x
    }
    return temp;
}
16. GCD (Greatest Common Divisor) between 2 numbers. Euclid’s algorithm

Pseudo Code of the Algorithm-

Step 1: Let a, b be the two numbers

Step 2: a mod b = R

Step 3: Let a = b and b = R

Step 4: Repeat Steps 2 and 3 until a mod b is 0

Step 5: GCD = b

Step 6: Finish

function gcd(a, b) {
var R;
while ((a % b) > 0) {
R = a % b;
a = b;
b = R;
}
return b;
}

17. Algorithm for checking whether a number is prime or composite

 Step 1: If 0,1 or 2, they are prime.


 Step 2: Iterative, from 2 to n/2, if n mod i == 0, then it’s not prime. Stop.

if (n == 0 || n == 1 || n == 2) {
isPrime = false;
}
else {
for (i = 2; i <= n / 2; ++i) {
if (n % i == 0) {
isPrime = false;
break;
}
}
}
if (isPrime)
cout << n << " is a prime number";
else
cout << n << " is not a prime number";

18. Algorithm for generating the first N prime numbers ???

19. Babylonian algorithm for extracting the square root

1. Select a precision level e (for example, 0.00001).


2. Initiate x=N and y=1.
3. While |x-y|/|x| > e, repeat x=(x+y)/2, y=N/x.
4. The result is x.

float sqRoot(float N) {

   float x = N, y = 1;              //initial guess as number and 1

   float precision = 0.000001;           //the result is correct


upto 0.000001

   while(abs(x - y)/abs(x) > precision) {

      x = (x + y)/2;

      y = N/x;

   }

   return x;

20. Algorithm for decomposition of a number into separate digits

Let d be the digit and N the number. d = N mod 10. N = N div 10. Write d, repeat until N=0.
while (number > 0)
{
int digit = number % 10;
number /= 10;
//print digit
}

21. Conversion of integer numbers in base 10 to another base

1. X is the number in base 10, b is the new base, i=0 and S is an empty string. While x>0
repeat steps 2 and 3;
2. R is the reminder of X/b. Add to S the (R+’0’).
3. Increase i by one, divide X by b.
4. Result is 0. Iterative, form the last element of S down to the first one, multiply the result
to 10 and add the number from string to it. That’s the answer.
int From10toB (int number, int b)

int i=0, x=number, rem=0;

String S;

while (x>0) {

rem=x % b;

S[i]=rem + ’0’;

i++;

x \= b;

};

int result=0;

for (int j=S.length(); j>0; j--) result=result * 10 + (S[i] –‘0’);

return result;

You might also like