CSE 211: Data Structures Lecture Notes VII



Similar documents
1) The postfix expression for the infix expression A+B*(C+D)/F+D*E is ABCD+*F/DE*++

Lecture 11 Doubly Linked Lists & Array of Linked Lists. Doubly Linked Lists

10CS35: Data Structures Using C

1. Relational database accesses data in a sequential form. (Figures 7.1, 7.2)

Data Structure with C

Short Notes on Dynamic Memory Allocation, Pointer and Data Structure

Stacks. Linear data structures

PES Institute of Technology-BSC QUESTION BANK

Analysis of a Search Algorithm

Data Structures Using C++ 2E. Chapter 5 Linked Lists

1 Abstract Data Types Information Hiding

BSc (Hons) Business Information Systems, BSc (Hons) Computer Science with Network Security. & BSc. (Hons.) Software Engineering

Common Data Structures

Lecture 12 Doubly Linked Lists (with Recursion)

CS 2412 Data Structures. Chapter 2 Stacks and recursion

Atmiya Infotech Pvt. Ltd. Data Structure. By Ajay Raiyani. Yogidham, Kalawad Road, Rajkot. Ph : ,

CS104: Data Structures and Object-Oriented Design (Fall 2013) October 24, 2013: Priority Queues Scribes: CS 104 Teaching Team

1. The memory address of the first element of an array is called A. floor address B. foundation addressc. first address D.

Data Structures Using C++ 2E. Chapter 5 Linked Lists

Questions 1 through 25 are worth 2 points each. Choose one best answer for each.

Linked List as an ADT (cont d.)

Lecture Notes on Binary Search Trees

LINKED DATA STRUCTURES

Abstract Data Type. EECS 281: Data Structures and Algorithms. The Foundation: Data Structures and Abstract Data Types

Linked Lists Linked Lists, Queues, and Stacks

Algorithms and Data Structures

C Dynamic Data Structures. University of Texas at Austin CS310H - Computer Organization Spring 2010 Don Fussell

The C Programming Language course syllabus associate level

KITES TECHNOLOGY COURSE MODULE (C, C++, DS)

Lecture Notes on Binary Search Trees

DATA STRUCTURES USING C

Glossary of Object Oriented Terms

Boolean Expressions, Conditions, Loops, and Enumerations. Precedence Rules (from highest to lowest priority)

DATA STRUCTURE - QUEUE

A binary search tree or BST is a binary tree that is either empty or in which the data element of each node has a key, and:

Data Structures and Algorithms C++ Implementation

Coding Rules. Encoding the type of a function into the name (so-called Hungarian notation) is forbidden - it only confuses the programmer.

STACKS,QUEUES, AND LINKED LISTS

Node-Based Structures Linked Lists: Implementation

Stack Allocation. Run-Time Data Structures. Static Structures

ADTs,, Arrays, Linked Lists

Linked Lists, Stacks, Queues, Deques. It s time for a chainge!

CmpSci 187: Programming with Data Structures Spring 2015

Data Structures and Algorithms Lists

Unordered Linked Lists

Module 2 Stacks and Queues: Abstract Data Types

Lecture 11 Array of Linked Lists

Illustration 1: Diagram of program function and data flow

C++ INTERVIEW QUESTIONS

Course: Programming II - Abstract Data Types. The ADT Stack. A stack. The ADT Stack and Recursion Slide Number 1

Binary Heap Algorithms

Sources: On the Web: Slides will be available on:

MAX = 5 Current = 0 'This will declare an array with 5 elements. Inserting a Value onto the Stack (Push)

7.1 Our Current Model

Algorithms and Data Structures Exercise for the Final Exam (17 June 2014) Stack, Queue, Lists, Trees, Heap

Habanero Extreme Scale Software Research Project

Unit Write iterative and recursive C functions to find the greatest common divisor of two integers. [6]

Memory Allocation. Static Allocation. Dynamic Allocation. Memory Management. Dynamic Allocation. Dynamic Storage Allocation

Course: Programming II - Abstract Data Types. The ADT Queue. (Bobby, Joe, Sue, Ellen) Add(Ellen) Delete( ) The ADT Queues Slide Number 1

DATA STRUCTURE - STACK

Introduction to Data Structures

Universidad Carlos III de Madrid

Queues Outline and Required Reading: Queues ( 4.2 except 4.2.4) COSC 2011, Fall 2003, Section A Instructor: N. Vlajic

Embedded Programming in C/C++: Lesson-1: Programming Elements and Programming in C

Lecture 10: Dynamic Memory Allocation 1: Into the jaws of malloc()

C++ Programming Language

Memory management. Announcements. Safe user input. Function pointers. Uses of function pointers. Function pointer example

Sequential Data Structures

Data Structures and Data Manipulation

Data Structure and Algorithm I Midterm Examination 120 points Time: 9:10am-12:10pm (180 minutes), Friday, November 12, 2010

EE2204 DATA STRUCTURES AND ALGORITHM (Common to EEE, EIE & ICE)

Introduction to Data Structures and Algorithms

Data Structures. Level 6 C Module Descriptor

5. A full binary tree with n leaves contains [A] n nodes. [B] log n 2 nodes. [C] 2n 1 nodes. [D] n 2 nodes.

Basic Data Structures and Algorithms

Programming languages C

Binary storage of graphs and related data

Ordered Lists and Binary Trees

Molecular Dynamics Simulations with Applications in Soft Matter Handout 7 Memory Diagram of a Struct

Storage Classes CS 110B - Rule Storage Classes Page 18-1 \handouts\storclas

Data Structures and Algorithms

QUEUES. Primitive Queue operations. enqueue (q, x): inserts item x at the rear of the queue q

Binary Search Trees (BST)

Tutorial on C Language Programming

PROBLEM SOLVING SEVENTH EDITION WALTER SAVITCH UNIVERSITY OF CALIFORNIA, SAN DIEGO CONTRIBUTOR KENRICK MOCK UNIVERSITY OF ALASKA, ANCHORAGE PEARSON

TREE BASIC TERMINOLOGIES

Data Structures and Algorithms

COMP 356 Programming Language Structures Notes for Chapter 10 of Concepts of Programming Languages Implementing Subprograms.

Sequences in the C++ STL

Quiz 4 Solutions EECS 211: FUNDAMENTALS OF COMPUTER PROGRAMMING II. 1 Q u i z 4 S o l u t i o n s

CS 2112 Spring Instructions. Assignment 3 Data Structures and Web Filtering. 0.1 Grading. 0.2 Partners. 0.3 Restrictions

CSE 326, Data Structures. Sample Final Exam. Problem Max Points Score 1 14 (2x7) 2 18 (3x6) Total 92.

Stack & Queue. Darshan Institute of Engineering & Technology. Explain Array in detail. Row major matrix No of Columns = m = u2 b2 + 1

- Easy to insert & delete in O(1) time - Don t need to estimate total memory needed. - Hard to search in less than O(n) time

Java Interview Questions and Answers

Linked Lists: Implementation Sequences in the C++ STL

Chapter 3: Restricted Structures Page 1

Transcription:

CSE 211: Data Structures Lecture Notes VII LINKED LISTS In the previous lectures we have seen the representation of ordered lists using an array and sequential mapping. These representations had the property that successive nodes of the data object were stored in a fixed distance apart. For example: If the element a ij of a table was stored at location L ij then a ij+1 was at the location L ij +c for a known constant c. Problems: The sequential storage schemes are adequate if one wished to access for given node in a table, insertion or deletions of nodes within a stack or queue. However insertions or deletions of arbitrary elements become expensive. If we have several ordered lists of varying sizes, by storing each list in a different array of maximum size, storage may be wasted. Additionally, in several cases we will need more than accessing the top item as in the stacks or inserting to the tail and accessing the head (queues). We need more general operations such as finding or removing any item in the list, inserting a new item at any point. Solution: The problem of data movement in sequential representations may be solved by using linked representations and dynamic memory allocation. Unlike a sequential representation where successive items of a list are located a fixed distance apart, in a linked representation each item of the list may be placed anywhere in memory. To access elements in the list in the correct order, with each element we store the location of the next element in that list. Associated with each data item in a linked representation there is a pointer to the next item. In modern languages providing built-in support for linked structures, the compiler associates a special storage with an object program which it leaves initially unassigned to any program variable. This area is usually called the heap or the dynamic storage pool. There is a heap manager program for the allocation of this storage from the heap at execution time. The allocated space can be referenced using pointers. Remember that pointer is just an abstraction for a machine address. Linked List Building Blocks: A linked list is an ordered sequence of elements called nodes. A list has a beginning, or head and an end, or tail. Every node on the list is the same type, although that type can take different forms. A central property of linked lists is their dynamic nature. Nodes can be added to or removed from a list at any time. Because the number of nodes cannot be predicted before run time. You should use pointers, rather than arrays, to achieve an efficient and reliable implementation. Nodes

Each node of a list consists of two parts. The first part holds the data. The first part holds the data. The data can be a simple variable or, more generally a structure ( or pointer to a structure) of some type. The second part is a pointer that indicatesthe location of the next node of the list. The nodes of a list can be implemented by a recursive structure. Consider the case where a single integer varaible is to be stored at each node of the list. struct simplenode int item; struct simplenode *next;}; typedef struct simplenode simple_t; class simplenode int item; simplenode *next;... }; In this case the integer variable item holds the actual data in each node, and the pointer variable next holds the address of the next node. item next In general, the item part may contain several pieces of data defined in a strcut type. We can generalize the list definition above as: struct generallist infotype item; struct generallist *next; }; typedef struct generallist glist_t; template <class infotype> class generallist infotype item; generallist *next;... }; We assume that info_type has been defined before. The problem with this kind of implementation is that for each type of list you must assign the individual components one by one when transfering information to and from the nodes. Ex. if s1 and s2 are both structures. In C, you cannot say s1=s2. You can assign only a single structure component in each statement. You can however write a function called assign and call it whenever needed. assign(s1,s2); info_type s1,s2; /* assign each component of struct 2 to struct 1 } This function carries out the detailed transfer of the individual structure components from 21 to s1. You can then build a series of generic list manipulation functions that use assign.

The problem with this approach is the performance. You will be transfering data among different memory locations. However you only need to transfer the address of the blocks of data corresponding to the structures. Solution: use a structure composed of a pair of pointers. The first pointer points to the data, the second points to the next item. struct node infotype * item; struct node *next; }; typedef struct node node_type; template <class infotype> class Node infotype * item; Node *next;... }; item next Manipulation of Linked Lists The manipulation of linked lists involves allocating storage for nodes (in C using malloc) and assigning data and/or pointers so that the list is properly formed. List's boundary conditions must be decided. In other words how are the head and tail of a list will be indicated. For the representation of the tail NULL pointer can be used (show it on the example) but for the head different approaches are possible. Define a pointer variable to hold the starting adress of the list. Define a special header node with the same structure. In this case the next element of the header node indicates the beginning of the list. (item part is unused - a small waste) Define a header node with a separate structure which holds exactly the information required. In this case other information related to the list such as number of elements in the list can be added to the header.

struct head int length; node_type *first, *last; } typedef struct head head_type; template <class infotype> class LinkedList int length; Node<infoType> *first,*last; int insert(infotype *data) int append(infotype *data) int delete(node *ptr) } If a symmetric header is used: If a custom head is used: (length, last, first) Operations on One-way Lists and their Implementations Allocating Memory When an array is defined, storage is automatically allocated by the compiler. When you are using pointers, however you must allocate the storage. In C, two standard library functions are provided for this purpose. malloc--- allocates a single piece of storage space and leaves it uninitialized calloc() -- allocates entire set of storage locations and fills the total storage with zero char *malloc(size) -------- allocates size number of bytes and returns a pointer to the first Although it returns a character pointer it can be used to allocate space for any type of element not just characaters by applying a simple type casting Size is the value returned by the sizeof operator sizeof expression sizeof(type name)

Type casting: new_variable = (type_name) old_variable We will define a fucntion called MALLOC and use it in the algorithms #define MALLOC(x) ((x *) malloc(sizeof(x))) float *place; /* A float pointer place = (float *) malloc (sizeof(float)); place = MALLOC(float); place = new float[1]; Creating a new list 1. allocate memory for header node 2. set length to 0 3. set first and last nodes to NULL head_type *create() head_type *new_node; if (new _node = MALLOC(head_type) ) new_node ->length = 0; new_node -> first = new_node -> last = NULL; } return(new _node); /* adress of new list } Inserting a new element at the beginning of a list A) Create a storage for the new node 1. Create storage for a new list node; 2. Assign appropriate pointer values to the new node 3. Assign new values to the components of the header node. Example given at the lecture. /* create a storage for the new node node_type *alloc_node(info_type * val, node_type * ptr) node_type *new_node; if (new_node = MALLOC(node_type)) new_node -> item = val; new_node -> next = ptr;} return(new_node); }

B) Inserting a new element at the beginning of a list 1. Allocate memory for the new node and set it (if possible) 2. Link the first pointer of header to the new node (?last) 3. Increment length by 1 int insert_node (info_type *data, head_type *list) node_type *new_node; if (new _node = alloc_node(data, list->first)) list->first = new_node; /* link in new node if (list->length == 0) /* if this is the first node list-> last = new_node; /* set last pointer to new list->length ++; return(1); /* success } else return(0); /* error } Appending a new item to the end of a list Another common operation appends a new item to the end of a list. The before and after situations are diagrammed below. You know where to find the current last node in the list by means of the last pointer, which is maintained in the header block. Thus you only need to allocate memory for a new node and rearrange pointers accordingly. int append (info_type *data, head_type *list) node_type *new_node;/* append data to end of list if (new_node=alloc_node(data, NULL) /* allocation OK, append data item if (list -> length) /* if the list is not empty list->last->next = new_node; /* link in new node else /* otherwise list->first = new_node; /* set first pointer to new list -> last = new_node; /* update last pointer list -> length++; /* update list length return(1); /* success } else /* allocation problem return(0); /* error } BEFORE: AFTER:

Deleting Nodes Study yourself. Doubly Linked Lists Finding the predecessor of a node in a one-way list requires a linear search. We can add a pointer to its predecessor, to each node. It will consume more space but search will be faster. Sometimes you may need to move through a list from the end to the beginning by following pointers. Inorder to be able to do this we can define two pointers in each node; One points to the next and one points to the previous node. Length Last First Previous Item Next (HEADER ) (NODE) (a doubly linked list) For doubly linked lists, you need to develop a new set of routines that are analogous to those for ordinary (singly linked) lists. The function to create a new doubly linked list is nearly the same as that for singly linked lists, in that you have to change only the data types of the header pointers. Let us first define the doubly linked list node: struct doubly info_type *item struct doubly *next, *prev; } typedef struct doubly doubly_type; template <infotype> class doubly infotype *item doubly *next, *prev;... } Header Node: It does not need to change. We only need to change the type of pointers from node_type to doubly_type.

Operations on Doubly Linked Lists (Two-Way Lists) Create operation head_db_type *create_db() head_db_type *new_node; /* attempt to allocate memory if (new_node =MALLOC(head_db_type)) /* allocation OK, initialize the values new_node -> length = 0; new_node -> first = NULL; new_node ->last = NULL; } /* return the address of the new lıst return(new_node); } DoublyLinkedList() first = NULL; last = NULL; length = 0; } We also need to write a function which creates a new node. /* create a storage for the new doubly linked node doubly_type *alloc_db_node(val, prev, next) info_type *val; doubly_type *prev, *next; doubly_type *new_node; if(new_node=malloc(doubly_type)) new_node -> item = val; new_node -> prev = prev; new_node -> next = next; } return(new_node); } doubly( info_type *val, doubly *prv, doubly *nxt) item = val; prev = prv; next = nxt; } Using this function we can write insert and append functions: /* Insert node at the beginning of a doubly linked list

int insert_dbl ( info_type *data, head_db_type *list ) doubly_type *new_node; if (new_node = alloc_db_node(data, NULL, list->first)) if (list->length == 0) /* if this is the first node list->last = new_node; /* set the last pointer to the new else /* if not the first node link it in list->first->prev = new_node; /* set prev field of first node list->first = new_node; /*set the first pointer to the new } list->length++; return(1); /* success }else return(0); } /* error Previous field of the first node is 0 Next field of the last node is 0 (before insertion) (after insertion) Append a node to the end of the list Home study-- do it yourself

Deleting first node from a doubly linked list We assume that before calling the delete function you have checked the length of the list. The function retıurns the data field of the deleted node and frees the memory used by this Node. info_type *del_dbl(head_db_type *list) doubly_type *temp; info_type *data; /* delete first node temp= list->first; /* save the pointer data = temp->item; /* save the data list->first = temp->next; /* reassign the first pointer list->length--; /* update list length if (list->length ) /* if new list is not empty list->first->prev = NULL; /* set prev field of first item to NULL else /* otherwise list->last = NULL; /* set last pointer to NULL ; free((char )temp); /* free node storage return(data); } (before deletion ) (after deletion) LINKED LIST ADT IMPLEMENTATION IN C / List ADT Type Defintions typedef struct node void* dataptr; struct node* link; } NODE;

typedef struct int count; NODE* pos; NODE* head; NODE* rear; int (*compare) (void* argu1, void* argu2); } LIST; // Prototype Declarations LIST* createlist (int (*compare) (void* argu1, void* argu2)); LIST* destroylist (LIST* list); int addnode (LIST* plist, void* datainptr); bool removenode bool searchlist (LIST* plist, void* keyptr, void** dataoutptr); (LIST* plist, void* pargu, void** pdataout); bool retrievenode (LIST* plist, void* pargu, void** dataoutptr); bool traverse (LIST* plist, int fromwhere, void** dataoutptr); int listcount (LIST* plist); bool emptylist (LIST* plist); bool fulllist (LIST* plist); static int _insert (LIST* plist, NODE* ppre, void* datainptr); static void _delete (LIST* plist, NODE* ppre, NODE* ploc, void** dataoutptr); static bool _search (LIST* plist, NODE** ppre, NODE** ploc, void* pargu); // End of List ADT Definitions /* =============== createlist ============== Allocates dynamic memory for a list head node and returns its address to caller Pre compare is address of compare function used to compare two nodes. Post head has allocated or error returned

Return head node pointer or null if overflow LIST* createlist (int (*compare) (void* argu1, void* argu2)) // Local Definitions LIST* list; list = (LIST*) malloc (sizeof (LIST)); if (list) list->head = NULL; list->pos = NULL; list->rear = NULL; list->count = 0; list->compare = compare; } // if return list; } // createlist /* ================== addnode ================= Inserts data into list. Pre plist is pointer to valid list datainptr pointer to insertion data Post data inserted or error Return -1 if overflow 0 if successful 1 if dupe key int addnode (LIST* plist, void* datainptr) // Local Definitions bool found; bool success; NODE* ppre; NODE* ploc; found = _search (plist, &ppre, &ploc, datainptr); if (found) // Duplicate keys not allowed return (+1); success = _insert (plist, ppre, datainptr); if (!success) // Overflow return (-1); return (0); } // addnode /* =================== _insert ================== Inserts data pointer into a new node. Pre plist pointer to a valid list

ppre pointer to data's predecessor datainptr data pointer to be inserted Post data have been inserted in sequence Return boolean, true if successful, false if memory overflow static bool _insert (LIST* plist, NODE* ppre, void* datainptr) // Local Definitions NODE* pnew; if (!(pnew = (NODE*) malloc(sizeof(node)))) return false; pnew->dataptr pnew->link = datainptr; = NULL; if (ppre == NULL) // Adding before first node or to empty list. pnew->link = plist->head; plist->head = pnew; if (plist->count == 0) // Adding to empty list. Set rear plist->rear = pnew; } // if ppre else // Adding in middle or at end pnew->link = ppre->link; ppre->link = pnew; // Now check for add at end of list if (pnew->link == NULL) plist->rear = pnew; } // if else (plist->count)++; return true; } // _insert /* ================= removenode ================ Removes data from list. Pre plist pointer to a valid list keyptr pointer to key to be deleted dataoutptr pointer to data pointer Post Node deleted or error returned. Return false not found; true deleted bool removenode (LIST* plist, void* keyptr, void** dataoutptr) // Local Definitions bool found;

NODE* ppre; NODE* ploc; found = _search (plist, &ppre, &ploc, keyptr); if (found) _delete (plist, ppre, ploc, dataoutptr); return found; } // removenode /* ================= _delete ================ Deletes data from a list and returns pointer to data to calling module. Pre plist pointer to valid list. ppre pointer to predecessor node ploc pointer to target node Post dataoutptr pointer to data pointer Data have been deleted and returned Data memory has been freed void _delete (LIST* plist, NODE* ppre, NODE* ploc, void** dataoutptr) *dataoutptr = ploc->dataptr; if (ppre == NULL) // Deleting first node plist->head = ploc->link; else // Deleting any other node ppre->link = ploc->link; // Test for deleting last node if (ploc->link == NULL) plist->rear = ppre; (plist->count)--; free (ploc); return; } // _delete /* ================== searchlist ================= Interface to search function. Pre plist pointer to initialized list. pargu pointer to key being sought Post pdataout contains pointer to found data -or- NULL if not found Return boolean true successful; false not found bool searchlist (LIST* plist, void* pargu, void** pdataout) // Local Definitions bool found;

NODE* ppre; NODE* ploc; found = _search (plist, &ppre, &ploc, pargu); if (found) *pdataout = ploc->dataptr; else *pdataout = NULL; return found; } // searchlist /* ================== _search ================= Searches list and passes back address of node containing target and its logical predecessor. Pre plist pointer to initialized list ppre pointer variable to predecessor ploc pointer variable to receive node pargu pointer to key being sought Post ploc points to first equal/greater key -or- null if target > key of last node ppre points to largest node < key -or- null if target < key of first node Return boolean true found; false not found bool _search (LIST* plist, NODE** ppre, NODE** ploc, void* pargu) // Macro Definition #define COMPARE \ ( ((* plist->compare) (pargu, (*ploc)->dataptr)) ) #define COMPARE_LAST \ ((* plist->compare) (pargu, plist->rear->dataptr)) // Local Definitions int result; *ppre = NULL; *ploc = plist->head; if (plist->count == 0) return false; // Test for argument > last node in list if ( COMPARE_LAST > 0) *ppre = plist->rear; *ploc = NULL; return false; } // if while ( (result = COMPARE) > 0 ) // Have not found search argument location *ppre = *ploc; *ploc = (*ploc)->link;

} // while if (result == 0) // argument found--success return true; else return false; } // _search /* ================== retrievenode ================ This algorithm retrieves data in the list without changing the list contents. Pre plist pointer to initialized list. pargu pointer to key to be retrieved Post Data (pointer) passed back to caller Return boolean true success; false underflow static bool retrievenode (LIST* plist, void* pargu, void** dataoutptr) // Local Definitions bool found; NODE* ppre; NODE* ploc; found = _search (plist, &ppre, &ploc, pargu); if (found) *dataoutptr = ploc->dataptr; return true; } // if *dataoutptr = NULL; return false; } // retrievenode /* ================= emptylist ================ Returns boolean indicating whether or not the list is empty Pre plist is a pointer to a valid list Return boolean true empty; false list has data bool emptylist (LIST* plist) return (plist->count == 0); } // emptylist /* ================== fulllist ================= Returns boolean indicating no room for more data. This list is full if memory cannot be allocated for another node. Pre plist pointer to valid list Return boolean true if full false if room for node

bool fulllist (LIST* plist) // Local Definitions NODE* temp; if ((temp = (NODE*)malloc(sizeof(*(pList->head))))) free (temp); return false; } // if // Dynamic memory full return true; } // fulllist /* ================== listcount ================== Returns number of nodes in list. Pre plist is a pointer to a valid list Return count for number of nodes in list int listcount(list* plist) return plist->count; } // listcount /* ================== traverse ================= Traverses a list. Each call either starts at the beginning of list or returns the location of the next element in the list. Pre plist pointer to a valid list fromwhere 0 to start at first element dataptrout address of pointer to data Post if more data, address of next node Return true node located; false if end of list bool traverse (LIST* plist, int fromwhere, void** dataptrout) if (plist->count == 0) return false; if (fromwhere == 0) //Start from first node plist->pos = plist->head; *dataptrout = plist->pos->dataptr; return true; } // if fromwhere else // Start from current position

if (plist->pos->link == NULL) return false; else plist->pos = plist->pos->link; *dataptrout = plist->pos->dataptr; return true; } // if else } // if fromwhere else } // traverse /* ================== destroylist ================= Deletes all data in list and recycles memory Pre List is a pointer to a valid list. Post All data and head structure deleted Return null head pointer LIST* destroylist (LIST* plist) // Local Definitions NODE* deleteptr; if (plist) while (plist->count > 0) // First delete data free (plist->head->dataptr); // Now delete node deleteptr = plist->head; plist->head = plist->head->link; plist->count--; free (deleteptr); } // while free (plist); } // if return NULL; } // destroylist