advanced data structures using c++ 3

21
Advanced data structure using C++ Assignment-3 Q1:-Differenciate between dequeue and priority queues? ANS:-Dequeue:- A Double ended queue At a post office, when it is your turn, you need to fill up a form, step aside and get served when finished. Has operations that Add, remove, or retrieve entries At both its front and back Combines and expands the operations of queue and stack public interface DequeInterface { public void addToFront(Object newEntry); public void addToBack(Object newEntry); public Object removeFront(); public Object removeBack(); public Object getFront(); public Object getBack(); public boolean isEmpty(); public void clear(); } // end DequeInterface Priority queue:- Organizes objects according to priorities Contrast to regular queue in order of arrival Priority queue example – a hospital ER: assign a priority number to each patient to override the arrival time.

Upload: shaili-choudhary

Post on 26-Jun-2015

192 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Advanced data structures using c++ 3

Advanced data structure using C++

Assignment-3

Q1:-Differenciate between dequeue and priority queues?

ANS:-Dequeue:-

A Double ended queue

At a post office, when it is your turn, you need to fill up a form, step aside and get served when finished.

Has operations that

Add, remove, or retrieve entries

At both its front and back

Combines and expands the operations of queue and stack

public interface DequeInterface{ public void addToFront(Object newEntry);

public void addToBack(Object newEntry);public Object removeFront();public Object removeBack();public Object getFront();public Object getBack();public boolean isEmpty();public void clear();

} // end DequeInterface

Priority queue:-

Organizes objects according to priorities

Contrast to regular queue in order of arrival

Priority queue example – a hospital ER: assign a priority number to each patient to override the arrival time.

Priority can be specified by an integer

Must define whether high number is high priority or …

Low number (say 0) is high priority

Page 2: Advanced data structures using c++ 3

Other objects can specify priority

Object must have a compareTo method

public interface PriorityQueueInterface{ public void add(Comparable newEntry);

public Comparable remove();public Comparable get();public boolean isEmpty();public int getSize();public void clear();

} // end PriorityQueueInterface

Q2:-Expalin Dequeue and its application?

ANS:- Dequeue

The dequeue function dequeues a packet for sending. It returns the next packet that needs to be sent out on the output interface. This packet is determined by the scheduler in the queuing discipline. The scheduler can be very complicated for complex queuing disciplines like the CBQ. At the same time, it can be very simple too, as in the case of a FIFO queue. The dequeue function for a simple FIFO queuing discipline (in net/sched/sch_fifo.c) is shown below:static struct sk_buff *pfifo_dequeue(struct Qdisc* sch){ return __skb_dequeue(&sch->q);}

As shown in this example, the next packet in the queue is dequeued and returned, which is desired behavior from a simple FIFO.

The dequeue function for a priority FIFO is shown next.

static struct sk_buff *prio_dequeue(struct Qdisc* sch){ . . . for (prio = 0; prio < q->bands;prio++) { qdisc = q->queues[prio]; skb = qdisc->dequeue(qdisc); if (skb) { sch->q.qlen--; return skb;

Page 3: Advanced data structures using c++ 3

} } . . .}

As shown in this example, whenever the prio_dequeue function is called, packets from the highest priority queue are sent first. After all the packets in the highest priority level are sent, packets from the next priority level are dequeued. This required behavior is provided by the portion of the code given above.

Having discussed the dequeue function of the queuing disciplines, let us now see the places where the dequeue function is invoked. Whenever a packet is enqueued in dev_queue_xmit, the qdisc_wakeup function (in include/net/pkt_sched.h) is invoked in an attempt to send the packet that was just enqueued. qdisc_wakeup invokes the qdisc_restart function (in net/sched/sch_generic.c), which invokes the dequeue function of the queuing discipline attached to the device. The dequeue function returns the next packet that needs to be sent out on the interface. qdisc_restart then invokes hard_start_xmit of the device to send the packet down to the device. If hard_start_xmit fails for some reason, the packet is requeued in the queuing discipline. The requeue function is discussed in a later section.

qdisc_wakeup can also be invoked from the watchdog timer handlers in the CBQ, TBF and CSZ schedulers. In the dequeue function of these queuing disciplines, when a packet is dequeued to be sent on the output interface, a watchdog timer is initiated. If for some reason, qdisc_restart does not send the packet out in time, the watchdog timer will go off and qdisc_restart is called. For example, the setting of the TBF watchdog timer in tbf_dequeue (in net/sched/sch_tbf.c) is shown below:

static struct sk_buff *tbf_dequeue(struct Qdisc* sch){...

if (!sch->dev->tbusy) {.. del_timer(&q->wd_timer); q->wd_timer.expires = jiffies + delay; add_timer(&q->wd_timer);}...

This example shows the way the watchdog timer is set.

Page 4: Advanced data structures using c++ 3

Aplications:-

The A-steal algorithm implements task scheduling for several processors. The processor gets the first element from the deque. When one of the processor completes execution of its own threads it can steal a thread of

processor. It gets the last element from the deque of another processor and executes it.

Q4:-Differenciate between DFS and BFS?

ANS:- Breadth First Search (also known as BFS) is a search method used to broaden all the nodes of a

particular graph. It accomplishes this task by searching every single solution in order to examine and

expand these nodes (or a combination of sequences therein). As such, a BFS does not use a heuristic

algorithm (or an algorithm that searches for a solution through multiple scenarios). After all the nodes

are obtained, they are added to a queue known as the First In, First Out queue. Those nodes that have

not been explored are ‘stored’ in a container marked ‘open’; once explored they are transported to a

container marked ‘closed’.

Depth First Search (also known as DFS) is a search method that burrows deeper into a child node of a

search until a goal is reached (or until there is a node without any other permutations or ‘children’).

After one goal is found, the search backtracks to a previous node that has gone with a solution,

repeating the process until all the nodes have been successfully searched. As such, nodes continue to be

put aside for further exploration – this is called non-recursive implementation.

The features of the BFS are space and time complexity, completeness, proof of completeness, and

optimality. Space complexity refers to the proportion of the number of nodes at the deepest level of a

search. Time complexity refers to the actual amount of ‘time’ used for considering every path a node

will take in a search. Completeness is, essentially, a search that finds a solution in a graph regardless of

what kind of graph it is. The proof of the completeness is the shallowest level at which a goal is found in

a node at a definite depth. Finally, optimality refers to a BFS that is not weighted – that is a graph used

for unit-step cost.

A DFS is the most natural output using a spanning tree – which is a tree made up of all vertices and some

edges in an undirected graph. In this formation, the graph is divided into three classes: Forward edges,

pointing from a node to a child node; back edges, pointing from a node to an earlier node; and cross

edges, which do not do either one of these.

1. bfs uses queue implementation ie.FIFO dfs uses stack implementation ie. LIFO

Page 5: Advanced data structures using c++ 3

2. dfs is faster than bfs

3. dfs requires less memory than bfs

4. dfs are used to perform recursive procedures.

Q5:- How can we convert a general tree into binary tree?

ANS:- General Trees and Conversion to Binary Trees

General trees are those in which the number of subtrees for any node is notrequired to be 0, 1, or 2. The tree may be highly structured and thereforehave 3 subtrees per node in which case it is called a ternary tree.However, it is often the case that the number of subtrees for any node maybe variable. Some nodes may have 1 or no subtrees, others may have 3, some4, or any other combination. The ternary tree is just a special case of ageneral tree (as is true of the binary tree).

General trees can be represented as ADT's in whatever form they exist.However, there are some substantial problems. First, the number of referencesfor each node must be equal to the maximum that will be used in the tree.Obviously, some real problems are presented when another subtree is added toa node which already has the maximum number attached to it. It is alsoobvious that most of the algorithms for searching, traversing, adding anddeleting nodes become much more complex in that they must now cope withsituations where there are not just two possibilities for any node butmultiple possibilities. It is also possible to represent a general tree ina graph data structure (to be discussed later) but many of the advantages ofthe tree processes are lost.

Fortunately, general trees can be converted to binary trees. They don'toften end up being well formed or full, but the advantages accrue frombeing able to use the algorithms for processing that are used for binarytrees with minor modifications. Therefore, each node requires only tworeferences but these are not designated as left or right. Instead they aredesignated as the reference to the first child and the reference to nextsibling. Therefore the usual left pointer really points to the first childof the node and the usual right pointer points to the next sibling of thenode. One obvious saving in this structure is the number of fields whichmust be used for references. In this way, moving right from a node accessesthe siblings of the node ( that is all of those nodes on the same level asthe node in the general tree). Moving left and then right accesses all ofthe children of the node (that is the nodes on the next level of the generaltree).

Creating a Binary Tree from a General Tree

Page 6: Advanced data structures using c++ 3

Since the references now access either the first child or successive siblings,the process must use this type of information rather than magnitude as wasthe case for the binary search tree. Note that the resulting tree is abinary tree but not a binary search tree.

The process of converting the general tree to a binary tree is as follows:

* use the root of the general tree as the root of the binary tree

* determine the first child of the root. This is the leftmost node in thegeneral tree at the next level

* insert this node. The child reference of the parent node refers to thisnode

* continue finding the first child of each parent node and insert it belowthe parent node with the child reference of the parent to this node.

* when no more first children exist in the path just used, move back to theparent of the last node entered and repeat the above process. In otherwords, determine the first sibling of the last node entered.

* complete the tree for all nodes. In order to locate where the node fitsyou must search for the first child at that level and then follow thesibling references to a nil where the next sibling can be inserted. Thechildren of any sibling node can be inserted by locating the parent and theninserting the first child. Then the above process is repeated.

Given the following general tree:

A

B C D

K H I J E F

G

Page 7: Advanced data structures using c++ 3

The following is the binary version:

Traversing the Tree

Since the general tree has now been represented as a binary tree thealgorithms which were used for the binary tree can now be used for thegeneral tree (which is actually a binary tree). In-order traversals make nosense when a general tree is converted to a binary tree. In the generaltree each node can have more than two children so trying to insert theparent node in between the children is rather difficult, especially if thereare an odd number of children.

Pre-order

This is a process where the root is accessed and processed and then each ofthe subtrees is preorder processed. It is also called a depth-firsttraversal. With the proper algorithm which prints the contents of the nodes

A

B

K C

H

I

J

D

E

F

G

Page 8: Advanced data structures using c++ 3

in the traversal it is possible to obtain the original general tree. Thealgorithm has the following general steps:

* process the root node and move left to the first child.

* each time the reference moves to a new child node, the print should beindented one tab stop and then the node processed

* when no more first children remain then the processing involves the rightsub-tree of the parent node. This is indicated by the nil reference toanother first child but a usable reference to siblings. Therefore the firstsibling is accessed and processed.

* if this node has any children they must be processed before moving on toother siblings. Therefore the number of tabs is increased by one and thesiblings processed. If there are no children the processing continuesthrough the siblings.

* each time a sibling list is exhausted and a new node is accessed thenumber of tab stops is decreased by one.

In this way the resulting printout has all nodes at any given level startingin the same tab column. It is relatively easy to draw lines to produce the original general tree except that the tree is on its side with it's root atthe left rather than with the root at the top. The result of doing this traversal is shown below.

A

B

K

C

H

D

I

E

J

F

Page 9: Advanced data structures using c++ 3

B-Trees

A B-Tree is a tree in which each node may have multiple children andmultiple keys. It is specially designed to allow efficient searching forkeys. Like a binary search tree each key has the property that all keys tothe left are lower and all keys to the right are greater. Looking at abinary search tree :

20 10 5 15

from position 10 in the tree all keys to the left are less than 10 and allkeys to the right are greater than 10 and less than 20. So, in fact, the keyin a given node represents an upper or lower bound on the sets of keys belowit in the tree. A tree may also have nodes with several ordered keys. Forexample, if each node can have three keys, then it will also have fourreferences. Consider the node below:

: 20 : 40 : 60 : / | | \

In this node (:20:40:60:) the reference to the left of 20 refers to nodes withkeys less than 20, the reference between 20 & 40 refers to nodes with keysfrom 21 to 39, the reference between keys 40 & 60 to nodes with keys between41 and 59, and finally the reference to the right of 60 refers to nodes withkeys with values greater than 61.

This is the organisational basis of the B-Tree. For m references there mustbe (m-1) keys in a given node. Typically a B-tree is specified in terms ofthe maximum number of successors that a given node may have. This is alsoequivalent to the number of references that may occupy a single node, alsocalled the order of the tree. This definition of order is chosen because itmakes most of the explanations simpler. However, some texts define order asthe number of keys and therefore the number of references is m + 1. Youshould keep this in mind when (or if) you refer to these texts. If the nodeshown above is full then it belongs to an order 4 B-tree. Several otherconstraints are also placed upon the nodes of a B-tree:

Constraints-----------

G

Page 10: Advanced data structures using c++ 3

* For an order m B-tree no node has more than m subtrees

* Every node except the root and the leaves must have at least m/2 subtrees

* A leaf node must have at least m/2 -1 keys

* The root has 0 or >= 2 subtrees

* Terminal or leaf nodes are all at the same depth.

* Within a node, the keys are in ascending order

Putting these constraints on the tree results in the tree being builtdifferently than a binary search tree. The binary search tree isconstructed starting at the root and working toward the leaves. A B-tree isconstructed from the leaves and as it grows the tree is pushed upward. Anexample showing the process of constructing a B-tree may be the easiest wayto understand the implications of the constraints and the structure of thetree.

The tree will be of order 4 therefore each node can hold a maximum of 3 keys.The keys are always kept in ascending order within a node. Because the treeis of order 4, every node except the root and leaves must have at least 2subtrees ( or one key which has a pointer to a node containing keys which areless than the key in the parent node and a pointer to a node containingkey(s) which are greater than the key in the parent node). This essentiallydefines a minimum number of keys which must exist within any given node.

If random data are used for the insertions into the B-tree, it generallywill be within a level of minimum height. However, as the data becomeordered the B-tree degenerates. The worst case is for data which is sortedin which case an order 4 B-tree becomes an order 2 tree or a binary searchtree. This obviously results in much wasted space and a substantial loss ofsearch efficiency.

Deletions from B-trees

Deletions also must be done from the leaves. Some deletions are relativelysimple because we just remove some key from the leaf and there are still enoughkeys in the leaf so that there are (m/2-1) keys in total.

The removal of keys from the leaves can occur under two circumstances -- whenthe key actually exists in the leaf of the tree, and when the key exists in aninternal leaf and must be moved to a leaf by determining which leaf positioncontains the key closest to the one to be removed. The deletion of a single key which does not result in a leaf which does not have enough keys is normallyreferred to as deletion.

Page 11: Advanced data structures using c++ 3

When the removal of a key from the leaf results in a leaf (or when this occursrecursively an internal node with insufficient keys) then the process which will be tried first is redistribution. If the keys among three nodes can beredistributed so that all of them meet the minimum, then this will be done.

When redistribution does not work because there are not enough keys toredistribute, then three nodes will have to be made into two nodes throughconcatenation. This is the reverse of splitting. It may also recur recursively through the tree.

Efficiency of B-Trees---------------------

Just as the height of a binary tree related to the number of nodes throughlog2 so the height of a B-Tree is related through the log m where m is theorder of the tree:

height = logm n + 1

This relationship enables a B-Tree to hold vast amounts of data in just afew levels. For example, if the B-tree is of order 10, then level 0 canhold 9 pieces of data, level 1 can hold 10 nodes each with 9 pieces of data,or 90 pieces of data. Level 2 can hold 10 times 10 nodes (100), each with9 pieces of data for a total of 900. Thus the three levels hold a total of999. Searches can become very efficient because the number of nodes to beexamined is reduced a factor of 10 times at each probe. Unfortunately,there is still some price to pay because each node can contain 9 pieces ofdata and therefore, in the worst case, all 9 keys would have to be searchedin each node. Thus finding the node is of order log (base m) n but thetotal search is m-1 logm n. If the order of the tree is small thereare still a substantial number of searches in the worst case. However if mis large, then the efficiency of the search is enhanced. Since the data arein order within any given node, a binary search can be used in the node.However, this is not of much value unless the order is large since a simplelinear search may be almost as efficient for short lists.

It should be clear that although the path length to a node may be veryshort, examining a node for a key can involve considerable searching withinthe node. Because of this the B-Tree structure is used with very large datasets which cannot easily be stored in main memory. The tree actually resideson disk. If a node is stored so that it occupies just one disk block then itcan be read in with one read operation. Hence main memory can be used forfast searching within a node and only one disk access is required for eachlevel in the tree. In this way the B-Tree structure minimises the number ofdisk accesses that must be made to find a given key.

Page 12: Advanced data structures using c++ 3

Q6:-Explain doubly linked list with its Implementation?

ANS:- Overall Structure of Doubly-Linked ListsIf you wish to traverse a list both forwards and backwards efficiently, or if you wish, given a list element, to determine the preceding and following elements quickly, then the doubly-linked listcomes in handy. A list element contains the data plus pointers to the next and previous list items as shown in the picture below.

Of course we need a pointer to some link in the doubly-linked list to access list elements. It is convenient for doubly-linked lists to use a list header, or head, that has the same structure as any other list item and is actually part of the list data structure. The picture below shows an empty and nonempty doubly-linked list. By following arrows it is easy to go from the list header to the first and last list element, respectively.

Insertion and removal of an element in a doubly-linked list is in this implementation rather easy. In the picture below we illustrate the pointer changes for a removal of a list item (old pointers have been drawn solid and new pointers are dashed arrows). We first locate the previous list item using the previous field. We make the next field of this list item point to the item following the one in cursor

Page 13: Advanced data structures using c++ 3

position pos. Then we make the previous field of this following item point to the item preceding the one in the cursor position pos. The list item pointed to by the cursor becomes useless and should be automatically garbage collected.

In a pseudo-programming language we could write the following code:

remove(cursor pos) begin if empty list then ERROR("empty list.") else if cursor points at list header then ERROR("cannot remove the list header") else

pos previous next = pos next;

pos next previous = pos previous; endif end

Implementation:-

#include <iostream>#include <string>#include <iomanip>#include <stdio.h>

using namespace std;//template <class Object>

//template <class Object>

Page 14: Advanced data structures using c++ 3

class Node{ //friend ostream& operator<<(ostream& os, const Node&c);public: Node( int d=0); void print(){ cout<<this->data<<endl; }//private: Node* next; Node* prev; int data;

friend class LinkList;};Node::Node(int d):data(d){

}

//template <class Object>class LinkList{void create();public: //LinkList(); LinkList():head(NULL),tail(NULL),current(NULL) {create();} int base; //LinkList(const LinkList & rhs, const LinkList & lhs); ~LinkList(){delete current;}

const Node& front() const;//element at current const Node& back() const;//element following current void move(); void insert (const Node & a);//add after current void remove (const Node &a); void print();private: Node* current;//current Node* head; Node* tail;};

void LinkList::print(){ Node *nodePt =head->next; while(nodePt != head)

Page 15: Advanced data structures using c++ 3

{ cout<<"print function"<<endl; cout<<nodePt->data<<endl; nodePt=nodePt->next; }}//element at current

void LinkList::create(){ current = head = tail = new Node(0); current->next = current->prev = current;}

const Node& LinkList::back()const{ return *current;}//element after currentconst Node& LinkList::front() const{ return *current ->next;}

void LinkList::move(){ current = current ->next;}//insert after current void LinkList :: insert(const Node& a){ Node* newNode= new Node(); newNode->prev=current; newNode->next=current->next; newNode->prev->next=newNode; newNode->next->prev=newNode; current=newNode;}void LinkList::remove(const Node& a){ Node* oldNode; oldNode=current; oldNode->prev->next=oldNode->next; oldNode->next->prev=oldNode->prev; delete oldNode;}

//main file

Page 16: Advanced data structures using c++ 3

#include <iostream>#include <string>#include <iomanip>#include <stdio.h> #include "LinkedList.h"

using namespace std;

int main(){ int n; cout<<"How many Nodes would you like to create"<<endl; cin>>n;

LinkList list1 ;

list1.print(); for(int loop = 0;loop < n;++loop) { list1.insert(loop); } list1.print();}