7. Data Memory Model run-time stack - activation records added and removed as program runs (expands and shrinks in an orderly LIFO manner) space for global variables space for variables allocated at run-time (allocation and de-allocation requests occur in unpredictable order) static data automatic data heap data
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18. The malloc( ) Function ptr 100 Stack Heap Name Marks 100
19.
20.
21.
22.
23.
24.
25. What is the need for ADT, Data types and Data Structures?
90. Visualizing a Linked List marks next 180 100 140 start 100 75 140 85 180 95 230 100 x marks next marks next marks next Stack Heap
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114. Visualizing a Doubly Linked List prior next marks null 1 120 100 prior next marks 100 2 140 120 prior next marks 120 3 null 140 100 start 140 last
181. Circumstances When a Binary Tree Degenerates into a Linked List 10 15 12 7 8 18 6 20 Root
182.
183. Circumstances When a Binary Tree Degenerates into a Linked List A Lopsided Binary Tree With Only Right Subtrees 6 7 8 10 12 15 18 20
184.
185. Circumstances When a Binary Tree Degenerates into a Linked List A Lopsided Binary Tree With Only Left Subtrees 20 18 15 12 10 8 7 6
186.
187.
188. Case I – Deletion Of The Leaf Node 2 p 2 null 3 3 1
189.
190. Case II – Deletion Of a Node With a Single Child To delete node containing the value 3, where the right subtree of 3 is empty, we simply make the link of the parent of the node with the value 3 (node with value 5) point to the child of 3 (node with the value 2). Node to be deleted 5 4 3 2 Node to be deleted 5 4 3 2
191.
192.
193. Case III – Deletion Of a Node With Two Child Nodes y Delete node x r q x t s u z Before Deletion of Node x r q t y s u z After Deletion of Node x
215. Linear Search in a Linked List 100 1 120 2 140 3 160 4 180 5 200 6 220 7 null
216. Binary Search in a Binary Search Tree 4 6 5 7 3 1 2 N N N N N N N N 7 Search Value 7 Search Value 7 Search Value
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237. Trees - Insertion rb_insert( Tree T, node x ) { /* Insert in the tree in the usual way */ tree_insert( T, x ); /* Now restore the red-black property */ x->colour = red; while ( (x != T->root) && (x->parent->colour == red) ) { if ( x->parent == x->parent->parent->left ) { /* If x's parent is a left, y is x's right 'uncle' */ y = x->parent->parent->right; if ( y->colour == red ) { /* case 1 - change the colours */ x->parent->colour = black; y->colour = black; x->parent->parent->colour = red; /* Move x up the tree */ x = x->parent->parent; While we haven’t reached the root and x’s parent is red x->parent
238. Trees - Insertion rb_insert( Tree T, node x ) { /* Insert in the tree in the usual way */ tree_insert( T, x ); /* Now restore the red-black property */ x->colour = red; while ( (x != T->root) && (x->parent->colour == red) ) { if ( x->parent == x->parent->parent->left ) { /* If x's parent is a left, y is x's right 'uncle' */ y = x->parent->parent->right; if ( y->colour == red ) { /* case 1 - change the colours */ x->parent->colour = black; y->colour = black; x->parent->parent->colour = red; /* Move x up the tree */ x = x->parent->parent; If x is to the left of it’s granparent x->parent x->parent->parent
239. Trees - Insertion /* Now restore the red-black property */ x->colour = red; while ( (x != T->root) && (x->parent->colour == red) ) { if ( x->parent == x->parent->parent->left ) { /* If x's parent is a left, y is x's right 'uncle' */ y = x->parent->parent->right; if ( y->colour == red ) { /* case 1 - change the colours */ x->parent->colour = black; y->colour = black; x->parent->parent->colour = red; /* Move x up the tree */ x = x->parent->parent; y is x’s right uncle x->parent x->parent->parent right “uncle”
240. Trees - Insertion while ( (x != T->root) && (x->parent->colour == red) ) { if ( x->parent == x->parent->parent->left ) { /* If x's parent is a left, y is x's right 'uncle' */ y = x->parent->parent->right; if ( y->colour == red ) { /* case 1 - change the colours */ x->parent->colour = black; y->colour = black; x->parent->parent->colour = red; /* Move x up the tree */ x = x->parent->parent; x->parent x->parent->parent right “uncle” If the uncle is red, change the colours of y, the grand-parent and the parent
241. Trees - Insertion while ( (x != T->root) && (x->parent->colour == red) ) { if ( x->parent == x->parent->parent->left ) { /* If x's parent is a left, y is x's right &apo
Editor's Notes
Dynamic memory allocation and de-allocation of memory is therefore, the responsibility of the programmer. The malloc( ) function allocates a block of memory on heap, and returns the starting offset of the block of memory allocated on the heap. This can be stored in a pointer declared as part of the stack, and access to the heap variable can be had using this pointer. When returning from the function, care must be taken by the programmer to return the storage occupied by the heap variable back to the heap. This is done using the function free( ) to which the pointer pointing to the heap variable is passed as an argument. The free( ) function de-allocates the block of memory on the heap used by the heap variable, and returns it back to the heap. If the call to the function free( ) is not issued before returning from the function, the pointer (stack variable) pointing to the heap variable will be destroyed when returning from the function, and therefore, the address to the heap variable will be lost. There will then be no way to de-allocate this block of memory on the heap, and return it back to the heap. This amount of memory will not be available for future use by other applications. This is what is referred to as a memory leak.
The size of the stack cannot grow to accommodate these runtime variables as the stack size is determined at the time of compilation. Therefore, dynamically created variables are accommodated into another area of memory called the heap or free store.
One way of determining the size of the structure marks_data and pass it as an argument to malloc() is to determine the size of the element name (11 bytes) and marks (2 bytes or 4 bytes) depending on the platform. Therefore, the size argument to be passed to malloc() can be 13 bytes or 15 bytes. Rather than count the number of bytes constituting the structure marks_data that is platform dependent, a better way should be for the program to determine the size of the elements constituting the structure marks_data based on the platform. This is where the sizeof( ) operator comes into the picture. What we had requested malloc() in the aforesaid example is a block on the Heap representing the structure marks_data and accordingly this structure on the heap was allocated.
In diagram (a), 10 is the current top element of the stack. If we add any element in the stack, it will be placed on top of 10, and if we delete an element, it will be 10 that is on top of the stack.
If a stack is empty, and it contains no element, it is not possible to pop the stack. Therefore, before popping an element, you must ensure that the stack is not empty. As the definition of a stack does not presuppose the number of elements in it, there is no upper limit on the number of elements in the stack, memory constraints notwithstanding.
Therefore, implementing a stack as an array prohibits the growth of the stack beyond the finite number of elements that the declared array can contain.
To understand queues in a better way, consider a queue containing three elements as shown if figure (a). If you want to add element 4 to this queue, you can do so only at the rear end of the queue as shown in figure (b). Now, if you remove an element from this queue, it should be element 1 that is to be deleted because this is the element that has come first in the queue and is at the front. After deleting 1, element 2 will be at the front as shown in figure (c).
You can insert a new node at the end of the list after the last node that is pointed to by pointer rear. You must take care when you insert an element into an empty queue as in this case you need to adjust the front pointer as well to point to this element.
Whenever you remove an element from a queue, you must ensure that the queue is not empty. If you are deleting the last element, you must ensure that q->rear = null to indicate that the queue is now empty.
Point 4: If we used the statement r= r+1; the value of r would be 5, but because it is a circular queue, the value of r should be 0. This can be achieved by using the statement:- r = (r+1)%QUEUE_SIZE;
The first node at address 100 (fictitious memory addresses) is referenced by a pointer called start (declared on the stack) . Once you are able to access the first node through start , you would be able to access all subsequent nodes through next . The pointer next of the last node points to no node in particular, and therefore contains the value NULL .
above For example, we wish to use a data structure to represent a person, and all of his or her descendants. Assume that the person’s name is Rajeev and that he has three children, Ravi, Vijay and Anjali. Ravi has three children Ramesh, Suresh and Sukesh. And Vijay has Arvind.
A search in such lopsided trees would degenerate into a linear search, and such a tree bears the functionality of a linked list. Such lopsided trees are not efficient from the perspective of search efficiency
You should also note that this type of deletion maintains the binary search tree but increases the height of the tree. Thus, it increases the time required for a search. Hence, to optimize searching through a binary search tree, you need methods that make the left and the right subtrees as balanced as possible.
In the calling routine, you can check whether the returned value of p is null or not. If it is null, the calling routine can give a message that the searched value is not there in the tree. The maximum number of comparisons in a binary search tree is equal to the depth of the tree whereas in the case of a linear linked list, the maximum number of comparisons is equal to the number of nodes in the list.
Consider the worst-case scenario of searching for the value 7 in the linked list. This would entail starting with the first node in the list and progressing linearly through the subsequent nodes till one comes to the value being searched for, which is 7. This would involve a maximum of 7 searches.
Consider the scenario of searching for the same value 7 in a balanced binary search tree. The search begins at the root node. Since the value being searched for is greater than the value in the root node, you need to search from the top of the right subtree to locate 7. Since the value being searched is also greater than the value at the top of the right subtree, you move to the top of the next right subtree of the current subtree where the search value 7 is located.