+ All Categories
Home > Documents > Lecture 4

Lecture 4

Date post: 02-Sep-2015
Category:
Upload: miguel-covarrubias
View: 212 times
Download: 0 times
Share this document with a friend
Description:
Lecture 4
Popular Tags:
54
Wednesday, April 12 th • Basic Linked Lists • Advanced Linked Lists – Tail Pointers – Doubly-linked Lists • Copy Constructors
Transcript
  • Wednesday, April 12thBasic Linked ListsAdvanced Linked ListsTail PointersDoubly-linked ListsCopy Constructors

  • Our AlgorithmSo whats our algorithm for adding an animal to our list?Request a new empty house to store our new animal.2. Put our animal in the empty house.3. Set the note in the new house to point to the last house where we put an animal.4. Update our chalk-board with the address of the newest house.We can do the same thing with C++

  • Linked Lists in C++We represent each house with a C++ struct:

    struct house{ string name; // animal were holding house *next; // address of next house};We can create linked lists in C++ too!

    We use the new command to ask for a new struct to hold a new animal.

    We use a special chalk board pointer to keep track of the last animal added to the list.

    We use the NULL pointer to identify the last struct in the list.

  • To add an animal to a linked listRequest a new empty house to store our new animal.2. Put our animal in the empty house.3. Set the note in the new house to point to the last house where we put an animal.4. Update our chalk-board with the address of the newest house. struct new struct. pointernew structstructchalkboard pointerstruct.house *chalkBoard; // global, points to top struct

    void add_animal(string animal){

    }struct house{ string name; house *next; }; house *latest = new house; // get new struct latest->name = animal; // store the animal latest->next = chalkBoard; // refer to last struct chalkBoard = latest; // point chalkboard to new struct

  • Our first Linked Liststruct house{ string name; house *next; };

    house *chalkBoard; // global

    void add_animal(string animal){ house *latest = new house; latest->name = animal; latest->next = chalkBoard; chalkBoard = latest; }

    void main(void){ chalkBoard = NULL; add_animal(cow); add_animal(emu); add_animal(mouse);}

    000010000000100400001008000012000000120400001208000014000000140400001408000002000000020400000208NULLcowHey Operating System I need about 20 bytes to hold a house struct.Sure. Ill reserve 20 bytes of memory for you at address 1200.cowNULLlatest->

  • Our first Linked Liststruct house{ string name; house *next; };

    house *chalkBoard; // global

    void add_animal(string animal){ house *latest = new house; latest->name = animal; latest->next = chalkBoard; chalkBoard = latest; }

    void main(void){ chalkBoard = NULL; add_animal(cow); add_animal(emu); add_animal(mouse);}

    0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081200emuHey Operating System I need about 20 bytes to hold a house struct.emu1200Sure. Ill reserve 20 bytes of memory for you at address 1000.latest->

  • Our first Linked Liststruct house{ string name; house *next; };

    house *chalkBoard; // global

    void add_animal(string animal){ house *latest = new house; latest->name = animal; latest->next = chalkBoard; chalkBoard = latest; }

    void main(void){ chalkBoard = NULL; add_animal(cow); add_animal(emu); add_animal(mouse);}

    0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081000mouseHey Operating System I need about 20 bytes to hold a house struct.mouse1000latest->Sure. Ill reserve 20 bytes of memory for you at address 1400.

  • Each struct holds an animals name and a next pointer that points to the next item in the list.The last struct in the list has a next pointer of NULL.

    This means end of list.Our chalkboard pointer (also called a head pointer) points to the first struct in the list.Our first Linked List0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081400mouse1000

  • Heres our algorithm:Now lets learn how to iterate through the items in the list. This is called traversing the list.Our first Linked List0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081400mouse1000Create a pointer called cur. Set cur to the value of the chalkboard pointer. 3. While the cur pointer is not NULLA. Print the animals nameB. Set the cur pointer to point to the next struct in the list. 4. Were done (at end of the list)!

  • Our first Linked List0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081400mouse1000Create a pointer called cur. Set cur to the value of the chalkboard pointer. 3. While the cur pointer is not NULLA. Print the animals nameB. Set the cur pointer to point to the next struct in the list. 4. Were done (at end of the list)!Create a pointer called cur. Set cur to the value of the chalkboard pointer. 3. While the cur pointer is not NULLA. Print the animals nameB. Set the cur pointer to point to the next struct in the list. 4. Were done (at end of the list)! house *cur; cur = chalkBoard; while (cur != NULL){

    }cout name;cur = cur->next;

  • Our first Linked List0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081400mouse1000struct house{ string name; house *next; };

    house *chalkBoard; // global

    void traverse(void){ house *cur; cur = chalkBoard;

    while (cur != NULL) { cout name; cur = cur->next; }}

    void main(void) { ... traverse();}

    14001400 != NULLcur->mousecur->

  • Our first Linked List0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081400mouse1000struct house{ string name; house *next; };

    house *chalkBoard; // global

    void traverse(void){ house *cur; cur = chalkBoard;

    while (cur != NULL) { cout name; cur = cur->next; }}

    void main(void) { ... traverse();}

    14001000 != NULLmousecur->emu

  • Our first Linked List0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081400mouse1000struct house{ string name; house *next; };

    house *chalkBoard; // global

    void traverse(void){ house *cur; cur = chalkBoard;

    while (cur != NULL) { cout name; cur = cur->next; }}

    void main(void) { ... traverse();}

    14001200 != NULLmousecur->cowemu

  • Our first Linked List0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081400mouse10001400NULL != NULLmousecowemu

  • Our first Linked List0000100000001004000010080000120000001204000012080000140000001404000014080000020000000204000002081400mouse10001400Question: Lets say I have 1000 items in my list.

    What do I have to do to access (e.g. print out) the 912th item?Answer: Starting with the head pointer, you have to follow 912 links before you can access that item.

    This is a drawback of Linked Lists that we dont have with arrays.

  • A Linked List ClassOur linked list class will allow the user to:Construct the listDestruct the listInsert new entries at the top of the listInsert new entries at the end of the listDelete entries from the listFind an entry in the listPrint out the contents of the listIn our next example, well define a simple linked list class to hold student information.

  • A Student Linked List Class struct node { string name; int id;

    node *next;};

    class CLL// Linked List Class{public: CLL();// constructor bool insert_top(const string &name,int id); bool insert_end(const string &name,int id); bool delete_item(const string &name); bool find(const string &name, int &id) const; void print_list(void) const; ~CLL();// destructor

    private: node * m_head; // head pointer};main(){ CLL c; c.insert_end("carey",400683948); c.insert_end("gwen",987654321); int id; if (c.find("gwen",id) == true) cout

  • Linked List: Constructorclass CLL// Linked List Class{public: CLL(void); // constructor ...private: node * m_head; // head pointer};

    CLL::CLL(){ // init list by // setting head to // NULL

    m_head = NULL;}

    Our linked list class constructor is responsible for initializing the head of the linked listmain(){ CLL c; // ctor called c.insert_end("carey",400683948); c.insert_end("gwen",987654321); int id; if (c.find("gwen",id) == true) cout

  • Inserting Nodes Into a Linked ListThere are three different places you can insert into a new node into a linked list:

    at the top of the list in the middle of the list at the end of the listInserting a new node at the top:m_head Allocate a new node using new.1000100020002000221022102. Add data to the new node.

    3. Set new nodes next pointer to point to previous root node. 4. Set the root pointer to point to the new node.

  • Inserting at the Topbool CLL::insert_top ( const string & name, int id ) { node *ptr; ptr = new node; if (ptr==NULL) return(false); ptr->name = name; ptr->id = id; ptr->next = m_head; m_head = ptr; return(true); }Lets work this one out on the chalk boardmain(){ CLL c; c.insert_top("carey",400683948); c.insert_top("gwen",987654321); ...}

  • Inserting in the Middle/EndInserting a new node in the middle/end:m_head NULLCase A: If the list is empty, then use the insert@top algorithm we just saw:

  • Inserting in the Middle/EndInserting a new node in the middle/end:1. Allocate a new node using new.2. Add data to the new node.3. Traverse down the list until you find the node above where you want to insert your new node. 5. Set the above nodes next pointer to point to the new node. 4. Set the new nodes next pointer to the value of the above nodes next pointer.m_head 100010001400160014001600NULLCase B: If the list is not empty, then:

  • Inserting at the Endbool CLL:insert_end( const string &name, int id ) { if (m_head == NULL) return(insert_top(name,id));

    // locate last node in list node * temp = m_head; while (temp->next != NULL) temp = temp->next; // allocate new node & set val node * temp2 = new node; if (temp2==NULL) return(false); temp2->name = name; temp2->id = id; // link the node into the list temp2->next = NULL; temp->next = temp2; return(true); }You can work through this code as an exercise (or come to O.H.)main(){ CLL c; c.insert_end(al",12345); c.insert_end(ed",67589); ...}

  • Deleting a Node3. Free the first node of the linked list (via the temporary pointer) using the delete command.m_head 10001000140016001400NULLCase A: If the target node is the first node in the list:2. Set the root pointer equal to the val of the first nodes next pointer.Lets say we want to delete the node that holds Tim (he dropped out).And youre done!1. Create a temporary pointer to point to the first node.

  • Deleting a Node2. Set the before nodes next pointer to the value of the target nodes next pointer.3. Use the delete command to free the target node.m_head 100010001400160014001600NULLCase B: If the target node is not the first node:1. Traverse down the list to locate the target node and the node before the target in the list. (use 2 pointers)Lets say we want to delete the node that holds Lyn (she dropped out).And youre done!

  • The Linked List Destructor3. While cur != NULLm_head 10001000140016001400NULL2. Set cur equal to the head pointer1. Create two pointers: cur and tempWhen were done with our list, we have to traverse the list and free each node one at a time.

    Set temp equal to cur->nextUse the delete command to free curSet cur equal to temp 10001000 != NULL1400Operating System, please free the memory at address 1000.Ok Boss. 1400 != NULL1600Operating System, please free the memory at address 1400.No sweat.1600 != NULL4. And were done!Operating System, please free the memory at address 1600.Consider it gone.NULL != NULL

  • Find an Item/Printing the ListTo find an item in the list, you can do a simple traversal of the list and compare each item in the list with the value youre searching for.Similarly, to print out the contents of a list, you cam simply do a traversal of each node and print its contents.

  • Linked Lists and Tail PointersJust as the head (root) pointer points to the first node in the list, a tail pointer points to the last node in the list. If you keep a tail pointer in your linked list ADT, then you can more quickly insert at the end of the list.Question: What components of our CLL class would need to change to use a tail pointer.

  • Doubly-linked ListsA doubly-linked list has both next pointers and previous pointers in every node: The big benefit of doubly-linked lists: You can move up or down through the list very easily. A singly linked list only allows us to move down easily.

  • Doubly-linked Lists: What Changes?Every time we insert a new node or delete an existing node, we must update three sets of pointers: 1. The new nodes next and previous pointers. 2. The previous nodes next pointer.3. The following nodes previous pointer.Obviously, we still have special cases if we insert or delete nodes at the top or the bottom of the list. NULL NULLPreviousNodeFollowingNode

  • Class Challenge #1Write a function called insert that accepts three NODE pointers as arguments:

    nodeanodebnewnode

    When your function is called, nodea is directly linked to nodeb. Your function should insert newnode between nodea and nodeb as we saw in the last example.struct NODE{ int val; NODE *next, *prev;};Remember there are 3 steps:1. Update newnodes next and prev ptrs. 2. Update nodeas next pointer.3. Update nodebs previous pointer.nodea nodeb

  • Copy ConstructionNext, were going to learn about how to initialize one class variable based on the value of another.In this example, we initialize the new variable b with the value of the existing variable a.When you do this, C++ will basically copy the value of every field in a to b. (shallow copy)In this case, the normal constructor for b is NOT called when we define the variable!

  • Copy ConstructionNext, were going to learn about how to initialize one class variable based on the value of another.Lets see this copying in action115When we initialize a new class variable based on the value of an existing class variable, this is called Copy Construction.Why? Because were constructing our new variable by copying the values from an old variable.

  • Copy ConstructionNext, were going to learn about how to initialize one class variable based on the value of another.You can define your own special Copy Constructor function if you need to.5If you dont define your own, then C++ will just copy each field from the old variable to the new variable (as weve seen).11Lets see how to create our own Copy Constructor function!

  • Copy Constructionclass Circ{public:Circ(float x, float y, float r){ m_x = x; m_y = y; m_rad = r;}

    float GetArea(void){ return(3.14159*m_rad*m_rad);}private:float m_x, m_y, m_rad;};Like a constructor, the Copy Constructor is a member function with the same name as the class.Circ(The copy constructor takes a single parameter: a const reference to another Circ variable. const Circ & oldVar)A simple Copy Constructor just copies the values from the old variable into the new variable.{ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}

  • Copy ConstructionLets see how our copy constructor works.115oldVar 115class Circ{public:Circ(float x, float y, float r){ m_x = x; m_y = y; m_rad = r;}

    float GetArea(void){ return(3.14159*m_rad*m_rad);}private:float m_x, m_y, m_rad;};Circ(const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}

  • Copy Constructionclass Circ{public:Circ(float x, float y, float r){ m_x = x; m_y = y; m_rad = r;}

    float GetArea(void){ return(3.14159*m_rad*m_rad);}private:float m_x, m_y, m_rad;};Circ(const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}A Copy Constructor is just like a regular constructor.However, it takes another object as a parameter instead of regular values.

  • Copy Constructionclass Circ{public:Circ(float x, float y, float r){ m_x = x; m_y = y; m_rad = r;}

    float GetArea(void){ return(3.14159*m_rad*m_rad);}private:float m_x, m_y, m_rad;};Circ(const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}Instead of:

    Circle b(a);

    You can use a simpler syntax if you like:

    Circle b = a;Even if you use an equal sign, C++ still calls the copy constructor function.

  • Copy Constructionclass Circ{public:Circ(float x, float y, float r){ m_x = x; m_y = y; m_rad = r;}

    float GetArea(void){ return(3.14159*m_rad*m_rad);}private:float m_x, m_y, m_rad;};Circ(const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}The copy constructor is not just used when you assign a new variable to an existing one:

    Circ b = a;Its used any time you make a copy of an existing class variable.Can anyone think of other times when a copy constructor would be used?

  • Copy Constructionclass Circ{public:Circ(float x, float y, float r){ m_x = x; m_y = y; m_rad = r;}

    float GetArea(void){ return(3.14159*m_rad*m_rad);}private:float m_x, m_y, m_rad;};Circ(const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}Can you guess when the Copy Constructor is called?1210Since were passing a by value to foo

    C++ will create a new variable called t and Copy Construct it from a.oldVar1210Once weve Copy Constucted our t variable, our function foo can run normally.

  • Copy ConstructionLets consider another class for a secondclass Squares{public: Squares(int n) { m_n = n; for (int j=0;j
  • Copy ConstructionLets consider another class for a secondclass Squares{public: Squares(int n) { m_n = n; for (int j=0;j
  • Copy Constructionclass Squares{public: Squares(int n) { m_n = n; for (int j=0;j
  • Copy Constructionclass Squares{public: Squares(int n) { m_n = n; for (int j=0;j
  • Copy ConstructionConsider our updated Squares class.It uses new and delete to dynamically allocate memory for its array.Ok so when would we ever need to write our own Copy Constructor?

    After all, C++ copies all of the fields for us automatically if we dont write our own!

  • Copy ConstructionWhen constructed, it uses new to allocate an array to hold the squares. When it is destructed, it uses delete to release its array. class Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j
  • Copy Constructionclass Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j
  • Copy Constructionclass Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j
  • Copy Constructionclass Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j
  • Copy Constructionclass Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j
  • Copy ConstructionAny time your class: Allocates dynamic memoryOpens system resources (like opening a file) You need to define your own copy constructor.The copy constructor must:Determine how much memory is allocated by the old variable.Allocate the same amount of memory in the new variable.

    2. Copy the contents of the old variable to the new variable, as appropriate.

  • Copy ConstructionGeneral copy constructor syntax:class SomeClass{ public:

    SomeClass (const SomeClass &src) { // 1. Allocate memory for the new variable // 2. Copy data from old variable into the new one }};

  • class Squares{public: Squares(int n) { } ~ Squares(){ delete[]m_sq; }

    // copy constructor syntax: Squares(const Squares &src) { m_n = src.m_n; m_sq = new int[m_n]; for (int j=0;j

  • class Squares{public: Squares(int n) { } ~ Squares(){ delete[]m_sq; }

    // copy constructor syntax: Squares(const Squares &src) { m_n = src.m_n; m_sq = new int[m_n]; for (int j=0;j


Recommended