cs204 – advanced programming pointers and linked lists part 2: advanced issues

37
CS204 – Advanced CS204 – Advanced Programming Programming Pointers and Linked Pointers and Linked Lists Lists Part 2: Advanced Issues Part 2: Advanced Issues

Upload: gannon-greatorex

Post on 30-Mar-2015

236 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

CS204 – Advanced ProgrammingCS204 – Advanced Programming

Pointers and Linked ListsPointers and Linked ListsPart 2: Advanced IssuesPart 2: Advanced Issues

Page 2: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Linked Lists: deleting...Linked Lists: deleting...

//iterativevoid DeleteList ( node *head) { node *temp; while (head != NULL) { temp = head->next; delete head; head = temp; }}

//recursivevoid DeleteList ( node *head) { if (head != NULL) { DeleteList(head->next); delete head; }}

head

2

Page 3: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Linked Lists: deleting...Linked Lists: deleting...head

//recursivevoid DeleteList ( node *head) { if (head != NULL) { DeleteList(head->next); delete head; }}

Unrolling the execution steps would look like this with the above list (after the 1st call):

DeleteList(ptr to node2) DeleteList(ptr to node 3) DeleteList(null) //returns immediately Delete ptr-to-node3 //"delete head" line Delete ptr-to-node2 Delete ptr-to-node1

Notice that statements which are aligned occur in the same call to and execution order is top to bottom.

1 2 3

3

Page 4: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

4

Adding a node to a sorted listAdding a node to a sorted list

You are given a linked list in which the elements are ordered. You want to add a node with a new element, but you want to keep the list still ordered.

To do so, you have to spot the place to insert the new node by traversing the list. Here, there are some cases to consider:– What if the list is empty?

– What if I need to add a node before the beginning of the list?

– What if I need to add a node somewhere inside the list?• Caution you cannot go back!

– What if I need to add a node at the end of the list?

Now we are going to see some methods for this task.

See ptrfunc.cpp for the implementation and a small demo

Page 5: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Adding a node to a sorted listAdding a node to a sorted listnode * AddInOrder(node * head, int newkey)// pre: list is sorted// post: add newkey to list, keep list sorted, return head of new list{ node * ptr = head; // loop variable

// if new node should be first, handle this case and return // in this case, we return address of new node since it is new head if (head == NULL || newkey < head->info) {

node * temp = new node; //node to be inserted temp->info = newkey;temp->next = head; //connect the restreturn temp;

}

// check node one ahead so we don't pass! while (ptr->next != NULL && ptr->next->info < newkey) {

ptr = ptr->next; } // postcondition: new node to be inserted just after the node ptr points

//now insert new node with newkey after where ptr points tonode * temp = new node; //node to be inserted temp->info = newkey;temp->next = ptr->next; //connect the restptr->next = temp;

return head;}

5

Page 6: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Alternative using the constructor: Adding a node to a sorted listAlternative using the constructor: Adding a node to a sorted listnode * AddInOrder(node * head, int newkey)// pre: list is sorted// post: add newkey to list, keep list sorted, return head of new list{ node * ptr = head; // loop variable

// if new node should be first, handle this case and return // in this case, we return address of new node since it is new head if (head == NULL || newkey < head->info) {

node * temp = new node; //node to be inserted temp->info = newkey;temp->next = head; //connect the restreturn temp;

}

// check node one ahead so we don't pass! while (ptr->next != NULL && ptr->next->info < newkey) {

ptr = ptr->next; } // postcondition: new node to be inserted just after the node ptr points

//now insert new node with newkey after where ptr points tonode * temp = new node; //node to be inserted temp->info = newkey;temp->next = ptr->next; //connect the restptr->next = temp;

return head;}

return new node(newkey, head);

ptr->next = new node(newkey,ptr->next);

6

Page 7: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Adding a node to a sorted list – Another Adding a node to a sorted list – Another alternative methodalternative method

node * AddInOrder(node * head, int newkey)// pre: list is sorted// post: add newkey to list, keep list sorted, return head of new list{ node * ptr = head; // loop variable

// if new node should be first, handle this case and return // in this case, we return address of new node since it is new head if (head == NULL || newkey < head->info) {

return new node(newkey, head); }

node * prev; //to point to the previous nodewhile (ptr != NULL && ptr->info < newkey)

{ prev = ptr; //hold onto previous node so we do not pass too far ptr = ptr->next;

} // postcondition: new node to be inserted between prev and ptr

//now insert node with newkey prev->next = new node(newkey,ptr);

return head;}

7

Page 8: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Deleting a single nodeDeleting a single node

• Several algorithms exist• We will cover one

– toBeDeleted points to the node to be deleted

– Need to keep another pointer for the previous node

– Special case if the first node to be deleted• No previous node• Head must be updated

• See the next slide for the code – Also in ptrfunc.cpp

9

head

toBeDeleted

Page 9: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Deleting a Deleting a single nodesingle node

void DeleteOneNode (node * toBeDeleted, node * & head)/* pre: toBeDeleted points to the node to be deleted from the list post: deletes the node pointed by toBeDeleted, updates head if changes */{

node * ptr;if (toBeDeleted == head) //if the node to be deleted is the first node{ head = head->next;

delete toBeDeleted;}else //if the node to be deleted is in the middle or at the end{ ptr = head;

while (ptr->next != toBeDeleted)ptr = ptr->next;

//after while, ptr points to the node just before toBeDeleted

//connect the previous node to the next node and deleteptr->next = toBeDeleted->next;delete toBeDeleted;

}}

10

toBeDeleted

head

Page 10: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Circular listsCircular lists

• Last node does not point to NULL, but points to the first node.• No change in the node struct definition, but processing the list is

different now• Actually there is no head or tail

– All nodes are semantically same– Keeping a pointer for any node would work– However, for the sake of visualization and ease of coding this

pointer can be for the pseudo-last node of the list.• First node of the list is next of last!

• For traversal the entire list, no sentinel check such as NULL– instead stop where you started– Of course, if the list is not empty; if empty, last is NULL

• See next slide for an example (also see ptrfunc.cpp)11

last

Page 11: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Circular listsCircular lists

• Count number of elements in a circularly linked list.

12

last

int countCircular (node * last)//pre: list is a circularly linked one, last points to the last node//post: returns number of nodes in the list{

if (last == NULL)return 0; //list is empty

int count = 0;node * ptr = last;do {

count++;ptr = ptr->next; //advance to the next line

} while (ptr != last); //loop until you reach where startedreturn count;

}

Page 12: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Doubly linked listsDoubly linked lists

• Each node does not only keep a pointer for the next node, but also for the previous node.

• Implications– In this way you can traverse the list in

both directions– Need to keep not only head, but also tail– Insert, delete operations are a bit more

complex

• Convention– Next of tail is NULL (as in regular linked

list)– Prev of head is also NULL

13

head tail

struct node {    int info;    node *next;

node *prev; };

Think of routines for building, insertion,

deletion, etc.

Page 13: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Other type of linked listsOther type of linked lists

• Circular and doubly linked lists

• Two dimensional linked lists• Multidimensional linked lists• Hybrid lists

– e.g. Head is a struct of a different type and includes a pointer for our list

– Two dimensional version of the above

• Circular and/or doubly linked versions of the above

• As you see, sky is the limit :-)14

Page 14: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

15

Linklist class with pointersLinklist class with pointers

An example class

Class definition (in the header file – say linkedlist.h)Definition of struct node can be either in the same

header file or in another included header file

class linkedlist {

private:node * head;

public: linkedlist (); void printList(); void addToBeginning(int n);

};

Page 15: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

16

Linklist class with pointersLinklist class with pointers

Class implementation (in a cpp file - say linkedlist.cpp):

linkedlist::linkedlist (){ head = NULL;}

void linkedlist::addToBeginning (int n){ node *ptr = new node(n,head); head = ptr;}

void linkedlist::printList (){ node * ptr = head; while (ptr != NULL)

{ cout << ptr ->info << endl; ptr = ptr->next;}cout << endl;

}

Notice here that head is updated, but we did not need addToBeginning to return a parameter or use reference variables because member functions already access the fields of the current object.

in main cpp file (linkedlistdemo.cpp):

linkedlist mylist, list2;mylist.AddToBeginning(5);list2.AddToBeginning(1);

Page 16: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Using Pointers: Be CarefulUsing Pointers: Be Careful

Remember to guard every pointer dereference so as not to access the contents of a NULL pointer. e.g.:

while (p != NULL && p->info < key)...

Thanks to short-circuit evaluation rule of C++; when p is null, p != NULL is evaluated to false and the rest of the boolean expression is not evaluated.

On the other hand, the following would crash your program when p is null pointer.

while (p->info < key)...

Page 17: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

18

Using Pointers: good practicesUsing Pointers: good practices

C++ allows programmers to define new types (actually an alias for a type) using the typedef statement:

  typedef int* IntPtr; IntPtr p1, p2; //same as int * p1, p2;   Avoids mistake of forgetting the * character

 

Simpler and more intuitive to use pointer reference parameter:  void get_space(IntPtr & ptr); same asvoid get_space(int* & ptr);

Page 18: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Using pointers for pass-by-referenceUsing pointers for pass-by-reference• You can use a pointer variable for the same job of a

reference parameter– As the argument, you pass the address of a regular variable– So that when you use dereferencing within the function, you reach and

change the argument's value.– This is more of C style, but know it!

void swap (int & x, int & y){

int temp = x;x = y;y = temp;

}

void swap (int * x, int * y){

int temp = *x;*x = *y;*y = temp;

}

This is called as:

int num1=13, num2=4;...swap (&num1, &num2); //num1 becomes 4, num2 becomes 13 19

Using reference parameters

Using pointers

Page 19: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

C style dynamic memory managementC style dynamic memory management• malloc (size)

– A function that dynamically allocates size bytes– Returns void pointer (to be cast to other types of pointers)

• calloc (num, length)– A function that dynamically allocates num*length bytes

• In order to allocate an array of num elements, length is calculated using sizeof function.

• sizeof (type_name) returns the number of bytes used by type_name.– Returns void pointer (to be cast to other types of pointers)

• free(ptr)– Deallocates (or frees) a memory block pointed by ptr.

• The memory block to be freed should have been previously allocated with malloc or calloc.

• You may need to include <stdlib.h> and <malloc.h>• The usage these memory blocks is mostly the same as the ones

allocated with new.

• Let's see an example use at malloc_calloc.cpp 20

Page 20: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Pointers and Dynamic ArraysPointers and Dynamic Arrays

Page 21: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

1D arrays with the 1D arrays with the newnew operator operatorTo dynamically allocate an array, specify the array size in squarebrackets [] after the type:

int *ptr;ptr = new int [20]; // dynamically allocate enough

// memory for an array of 20 ints. // ptr now points to the // 1st element of the array.

Instead of 20 (size of the allocated array), you can also use a user-defined variable:cin >> size;

ptr = new int [size];

Here be careful that memory allocation is dynamic, but the size of the array cannot be enlarged or reduced once the memory allocation is done

To free the memory allocated to a dynamically allocated array, you must include a pair of empty square brackets in the delete statement, just after the delete command:

delete [] ptr;

ptr

22

Page 22: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Memory allocation with the Memory allocation with the newnew operator operatorPoints to be carefulPoints to be careful

What happens if you don't have enough memory?

NULL pointer is returned

You need to check for that possibility

int * ptr;

ptr = new int [100000];

if ( ptr != NULL)

...

23

Page 23: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

24

Pointers and 2D Dynamic ArraysPointers and 2D Dynamic Arrays

Page 24: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

25

When we need 2-dimensional data for matrices, images etc, we have two option:

1) Create a 1-dimensional data, by using:data = new int [rows * columns];

Now data represents the 2D structure implicitly. For instance the element M[x,y] is found in data[x*columns+y].

[0…columns-1] indices belong to first row, [columns …2*columns-1] indices belong to 2nd row, etc.

2) Create a truly 2-dimensional data. In this case array indexing is easier.

Will see both cases

Page 25: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

26

Case 1) 1d dataCase 1) 1d data w/ class w/ class (See matrixclass.h, matrixclass.cpp, (See matrixclass.h, matrixclass.cpp,

matrixclassdemo.cpp)matrixclassdemo.cpp) class Matrix1D { private:

int rows, cols;int * data;

public:Matrix1D(int r, int c);int GetIndex(int i, int j);void SetIndex(int i, int j, int val);

};Matrix1D::Matrix1D(int r, int c){ rows = r;cols = c;int size = rows * cols;data = new int [size]; //this is a one long array of ints – 1D

}

int Matrix1D::GetIndex(int i, int j){ return data[i*cols+j];}

void Matrix1D::SetIndex(int i, int j, int value){ data[i*cols+j] = value;}

Usage in main:Matrix1D m(5,10); //a 5x10 matrix

m.SetIndex(0,5,33);cout << m.GetIndex(0,5) << endl;

Page 26: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Pointer to pointerPointer to pointer

• SyntaxType ** variable;

• Exampleint ** p;

p = new int *;

*p = new int;

**p = 12;

cout << **p; //Displays 12

• We can make use of pointer to pointer for the implementation of 2D arrays (see next)

27

p ? ?

p ?

p ?

p 12

Page 27: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

28

Case 2) 2d data allocation –Case 2) 2d data allocation – w/o classesw/o classesint ** M; int rows, columns, i,j;   cout<<"Enter the number of rows:"; cin >> rows; cout<<"Enter the number of columns:"; cin >> columns;   // M is an array of int pointers M = new int* [rows];

//each M[i] is a pointer (array of int)for (i = 0; i<rows; i++)

M[i] = new int [columns];  

cout << "Enter the elements" << endl; for (i = 0; i < rows; i++)

for (j= 0 ; j< columns ; j++) { cout<< '[' << i << ',' << j << "]: ";

cin >> M[i][j];  cout<< endl;

}   print_table(M, rows, columns);   for (i = 0; i< rows; i++) // Returning memory to free heap for reuse delete [] M[i]; delete [] M; }

 

Page 28: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

29

Case 2) 2d data allocation –Case 2) 2d data allocation – w/o classesw/o classesvoid print_table(int** values, int num_rows, int num_cols) {

int i, j;  

for (i = 0; i < num_rows; i++) {

for (j= 0 ; j< num_cols ; j++) cout << values[i][j] << " "; cout << endl;

} }

• Question: What happens if we change the values of the matrix elements in the above function?– e.g. values[2][1] = 100;

• The above code (this and prev. slide) is shown in matrixnoclass.cpp

Page 29: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

30

Case 2) 2d data allocationCase 2) 2d data allocation w/ class w/ class (See matrixclass.h, (See matrixclass.h, matrixclass.cpp, matrixclassdemo.cpp)matrixclass.cpp, matrixclassdemo.cpp)

class Matrix2D { private: int rows, cols; int ** data;

public: Matrix2D(int r, int c); int GetIndex(int i, int j); void SetIndex(int i, int j, int val);};

Matrix2D::Matrix2D(int r, int c){ rows = r; cols = c; data = new int* [r];

for (int i = 0; i<rows; i++) data[i] = new int[cols];}

int Matrix2D::GetIndex(int i, int j){ return data[i][j];}

void Matrix2D::SetIndex(int i, int j, int value){ data[i][j] = value;}

Full implementation is in matrixclass.h, matrixclass.cpp.

Usage in main:Matrix2D m(5,10); //a 5x10 matrix

m.SetIndex(0,5,33);cout << m.GetIndex(0,5) << endl;

Page 30: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Pointers and Static ArraysPointers and Static Arrays

Efficiency Issues

Page 31: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Pointers and ArraysPointers and Arraysint myarray[10]; //static (a.k.a. built-in) array definition

int *ptr;

ptr = myarray; //address stored in pointer is the address of the

// first element in array

OR

ptr = &myarray[0]; //equivalent and more clear

After that, you can refer to myarray[i] also as ptr[i]

See ptr_staticarrays.cpp for an example

32

Page 32: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Pointers and Arrays: Pointers and Arrays: IncrementIncrement

int students[10];

int *ptr;

ptr = students; //ptr points to students [0]

ptr =  &students[0]; //same as above

ptr++; //ptr points to students[1]

• ptr increments by the size of the type pointed by the pointer– in this case the pointer points to 4 bytes ahead (not 1 byte) to the

next integer

33

Page 33: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Pointer IncrementPointer Increment/Decrement/Decrement Depends on Pointed TypeDepends on Pointed Typechar c = 'z';     char *p;     //p points nowherep = &c; // p now points to c.    

p--; // p now points to the address of the BYTE in the runtime stack before c

p++; // p points to c again.

If the pointer pointed to integers:

int myintarr [20];int * p = myintarr;p++; // p now points to 4 BYTES ahead (when integers take 4 bytes)

This is the reason why we don’t just say: pointer p;We want the compiler to move the pointer by the size of the data type it points

to.

Actually, not only increment/decrement, any integer addition/subtraction works in the same manner 34

Page 34: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Pointers and 2D static arraysPointers and 2D static arraysint my2d [3][5]; //2D static array definition

//to have pointer for this array, we need an array of ptrs for each row

//and assign each row of 2D array to each element of ptr array

int * ptr2[3];

ptr2[0] = my2d[0];

ptr2[1] = my2d[1];

ptr2[2] = my2d[2];

int **ptr3 = ptr2; //ptr3 points to the pointer array

After that, you can refer to my2d[i,j] also as ptr3[i,j]

See ptr_staticarrays.cpp for an example

35

Page 35: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

PPointerointer use for efficiency - 1 use for efficiency - 1const int NUM_STUDENTS 10;

int students[NUM_STUDENTS];

int *p;

for (i=0; i < NUM_STUDENTS; i++)

cout << students[i];

or

p = &students[0];

for (i=0; i < NUM_STUDENTS; i++)

cout << *p++;

2nd one is direct access to memory.

1st one requires addition to calculate the address of array element each time.

Thus 2nd one is more efficient, use it!!

36

Page 36: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

37

Ptr use for efficiency - 2Ptr use for efficiency - 2• Assume we have a static 1D array which actually holds 2D data:

char img [width*height]; //grayscale image with pixel values 0-255

size = width*height;

for (i=0; i < size; i++)

{

if (img[i] > 200)

img[i] = 255; //assign a new gray value

}

char * ptr = &img[0]; //How much do you save??

for (i=0; i < size; i++) //Lets say size is 10,000.

{ //2*10,000 additions for array indexing if (*ptr > 200) //are saved replaced with 10,000

increments

*ptr=255;

ptr++;

}

Page 37: CS204 – Advanced Programming Pointers and Linked Lists Part 2: Advanced Issues

Ptr use for efficiency - 3Ptr use for efficiency - 3

Typical array/string copying routineNote that memory for destination has already been allocated in the

calling program

void my_strcpy (char * destination, char * source) {

char *p = destination;while (*source != '\0')

{*p++ = *source++; //I had told you not to use cryptic code

//but this piece of code is very common that everyone can understand it easily

}*p = '\0'; //why do we need this?

}38