Home

Linked Lists

   

The .NET Framework's Linked List

 

Introduction

A linked list is a collection with the following rules:

  • Each item in the list is called a node (this is not an actual rule but a habit or a suggestion)

Node

  • If the list is empty, it may have one item referred to as null
  • If the list was just empty, when a new node is added, that node becomes the first and last item
  • If the list has only one node, that node represents the first and the last item

    Node

  • If the list contains at least one node, whenever a new node is added, that new node is positioned as the last in the list. This is because the new node is added next to the existing node
  • If the list contains more than one node, each item holds a reference to the object next to it

Nodes of a Linked List

In reality, there are various types of linked lists. A singly linked list is a one-way directional list where each item points (only) to the item next to it (in a somewhat right direction). The description we just gave is conform to a singly linked list. Another type is the doubly linked list:

  • Each item in the list is called a node (again, this is not a real rule)
  • If the list is empty, it may have one item referred to as null or two items referred to as nulls
  • If a new node is added to an empty list, that node is added as the first in the collection
  • If the list contains one node, that node has two references to itself: one reference as the next and the other reference as its previous
  • If the list contains two nodes:
    • One node is the first. That first node holds a reference to the other node as its next
    • The other node is the last. That last node holds a reference to the first node as its previous item
  • If the list contains more than two nodes:
    • The first node holds a reference to the next node (in the right direction)
    • The last node holds a reference to the node previous to it (in the left direction)
    • Each node holds two references: one reference to the previous node and one reference to the next node

Nodes of a Linked List

The last type of linked list is called a circular linked list. This list is primarily created as either a singly linked list or a doubly linked list:

  • In a circular singly linked list, the list primarily follows the rules of a singly linked list. then:
    • If the list has two nodes, the first node holds a reference to the other node as its next and its previous node
    • If the list has more than one node:
      • The first node holds a reference to the last node as its previous object
      • The last node holds a reference to first node as its next

Circular Singly Linked List

  • In a doubly linked list, the list includes the rules of the doubly linked list and combines with those of the circular singly linked list:
    • The first node has a reference to the last node as its previous node
    • The last node has a reference to the first node as its next node
    • Each node has two references: its previous and its next nodes

Circular Doubly Linked List

ApplicationTopic Applied: Introducing Linked Lists

  1. Start Microsoft Visual Studio
  2. To create a new application, on the main menu, click FILE -> New Project...
  3. In the middle list, make sure Windows Forms Application is selected and change the Name to AltairRealtors1
  4. Click OK
  5. When asked whether you want to save the current solution, click Yes
  6. To create a new class, on the main menu, click PROJECT -> Add Class...
  7. Set the Name to RealEstateProperty
  8. Click Add
  9. Change the file as follows:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace AltairRealtors1
    {
        [Serializable]
        public class RealEstateProperty
        {
            public string PropertyNumber { get; set; }
            public string PropertyType   { get; set; }
            public string Address        { get; set; }
            public string City           { get; set; }
            public string State          { get; set; }
            public string ZIPCode        { get; set; }
            public short  Stories        { get; set; }
            public int    YearBuilt      { get; set; }
            public short  Bedrooms       { get; set; }
            public float  Bathrooms      { get; set; }
            public string Condition      { get; set; }
            public string SaleStatus     { get; set; }
            public double MarketValue    { get; set; }
            public string PictureFile    { get; set; }
    
            // To determine that two properties are the same,
            // we will test only the property number.
            // We assume that if two properties have the same number,
            // then it is the same property
            public override bool Equals(object obj)
            {
                RealEstateProperty rep = (RealEstateProperty)obj;
    
                if (rep.PropertyNumber == PropertyNumber)
                    return true;
                else
                    return false;
            }
    
    	// To avoid a compiler warning
            public override int GetHashCode()
            {
                return base.GetHashCode();
            }
        }
    }
  10. In the Solution Explorer, right-click Form1.cs and click Rename
  11. Type AltairRealtors.cs and press Enter twice
  12. Display the form and, from the Toolbox, add a list view to the form
  13. Right-click the list view on the form and click Edit Columns...
  14. Create the columns as follows:
     
    (Name) Text TextAlign Width
    colPropertyNumber Property #   65
    colCity City   75 
    colStories Stories Right 45
    colYearBuilt Year Right 40
    colBedrooms Beds Right 38
    colBathrooms Baths Right 40
    colCondition Condition   80
    colSaleStatus Status   70
    colMarketValue Value Right 75
  15. Click OK
  16. Design the form as follows:
     
    Altair Realtors - Properties Listing
    Control (Name) Anchor BorderStyle SizeMode  Text 
    ListView List View lvwProperties Top, Bottom, Left, Right      
    Button btnNewProperty Bottom, Left     New Real Estate Property... 
    PictureBox Picture Box pbxPicture Bottom, Right FixedSingle  Zoom   
    Button btnClose Bottom, Right      Close
    Form
    Text: Altair Realtors - Properties Listing
    StartPosition: CenterScreen
  17. Right-click the form and click Edit Groups...
  18. Create the groups as follows:
     
    Header Name
    Condominium lvgCondominium
    Townhouse lvgTownhouse
    Single Family lvgSingleFamily
  19. Click OK

Creating a Linked List

Although you can create a linked list collection class from scratch, to assist you, the .NET Framework provides a class named LinkedList and that is a member of the System.Collections.Generic namespace. LinkedList is a generic collection class with three constructors. The default constructor allows you to create an empty linked list. Here is an example of using it:

using System;
using System.Windows.Forms;
using System.Collections.Generic;

public class LinkedListExample : Form
{
    Button btnLinkedList;

    public LinkedListExample()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        btnLinkedList = new Button();
        btnLinkedList.Location = new System.Drawing.Point(12, 12);
        btnLinkedList.Text = "Linked List";
        btnLinkedList.Click += new EventHandler(btnLinkedListClicked);

        Controls.Add(btnLinkedList);
        Text = "Linked List Example";
        StartPosition = FormStartPosition.CenterScreen;
    }

    private void btnLinkedListClicked(object sender, EventArgs e)
    {
        LinkedList<double> numbers = new LinkedList<double>();
    }
}

public class Exercise
{
    public static int Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new LinkedListExample());
        return 0;
    }
}

Another constructor allows you to create a linked using an existing list. Its syntax is:

public LinkedList(IEnumerable<T> collection);

The argument can be a variable from any class that implements the IEnumerable<T> interface. Here is an example of using this second constructor:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
}

Fundamental Operations on a Linked List

 

Introduction to a Node as an Object

As mentioned already, it is a tradition to call an item of a linked list a node. To define a node as a true object, the .NET Framework provides the LinkedListNode sealed class:

public sealed class LinkedListNode<T>

This class has only properties, no methods.

The Number of Nodes of a List

The LinkedList class starts as follows:

public class LinkedList<T> : ICollection<T>, 
            		     IEnumerable<T>,
            		     ICollection, IEnumerable,
            		     ISerializable,
            		     IDeserializationCallback

As you can see, the LinkedList class implements the ICollection interface. This gives it a Count property that produces the number of nodes. Here is an example of accessing it:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);

    MessageBox.Show("There are " + numbers.Count.ToString() + " numbers in the list",
                    "Linked List",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Linked List

Adding a Node

The primary operation to perform on a linked list is to add a new node to it. To support it, the LinkedList class is equipped with various methods. One of them is named AddLast that is overloaded in two versions. One of them uses the following syntax:

public LinkedListNode<T> AddLast(T value);

This method expects the new value as argument. Here is an example of calling it:

using System;
using System.Windows.Forms;
using System.Collections.Generic;

public class LinkedListExample : Form
{
    Button btnLinkedList;

    public LinkedListExample()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        btnLinkedList = new Button();
        btnLinkedList.Location = new System.Drawing.Point(12, 12);
        btnLinkedList.Text = "Linked List";
        btnLinkedList.Click += new EventHandler(btnLinkedListClicked);

        Controls.Add(btnLinkedList);
        Text = "Linked List Example";
        StartPosition = FormStartPosition.CenterScreen;
    }

    private void btnLinkedListClicked(object sender, EventArgs e)
    {
        LinkedList<double> numbers = new LinkedList<double>();

        numbers.AddLast(148.24);
    }
}

public class Exercise
{
    public static int Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new LinkedListExample());
        return 0;
    }
}

Another version of this method is:

public void AddLast(LinkedListNode<T> node);

This version expects a LinkedListNode object as argument. Here is an example of calling it:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    LinkedList<double> numbers = new LinkedList<double>();
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);

    numbers.AddLast(number);
}

In the same way, you can use this method to add new items. Here are examples:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    LinkedList<double> numbers = new LinkedList<double>();

    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddLast(number);

    number = new LinkedListNode<double>(2222.06);
    numbers.AddLast(number);

    number = new LinkedListNode<double>(4.19);
    numbers.AddLast(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddLast(number);
}

Looking for a Node

 

Introduction

Because the LinkedList implements the ICollection interface, it inherits the Contains method. As a reminder, its syntax is:

public bool Contains(T value);

This method checks whether the linked list contains the (a) node that has the value passed as argument. If that node is found, the method returns true. Otherwise it returns false. Here is an example of calling it:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(2222.06);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddFirst(number);

    if( numbers.Contains(2222.06) == true )
        MessageBox.Show("The list contains 2222.06.",
                        "Linked List",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
    else
        MessageBox.Show("There is no such a number in the list.",
                        "Linked List",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);

This method works only if the type of the node is able to perform the comparison for equality. If you are using values of primitive types (int, char, double, DateTime, etc) or string, the method would work fine. If you are using your own class, make sure you override the Equals() method.

Finding a Node

While the Contains() method is used to look for a value in a linked list, it only lets you know whether the value was found. If you want to get the actual node that has that value, you can call the Find() method. Its syntax is:

public LinkedListNode<T> Find(T value);

When this method is called, it starts looking for the value in the linked list. If it finds it, it returns its node. If there is more than one node with that value, the method returns only the first node that has that value. Here is an example of calling this method:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(2222.06);
    numbers.AddFirst(number);

    numbers.AddFirst(2747.06);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddFirst(number);

    if( numbers.Find(2747.06) != null )
        MessageBox.Show("2747.06 was found in the list.",
                    "Linked List",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
    else
        MessageBox.Show("2747.06 is nowhere in the list.",
                    "Linked List",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Linked List

If the list contains more than one node that has the value but you prefer to use the last node, you can call the FindLast() method.

public LinkedListNode<T> FindLast(T value);

Once again, remember that these two methods are ready to work on primitive types. If you are using your own class for the type of node, you should (must) override the Equals() method.

Getting Each Node

As you can see, the LinkedList class doesn't implement the IList interface, which means it doesn't have an Item property. As we have seen with the AddLast() method and as we will see in the next sections, each method used to add a node is provided in two versions. One of the versions returns a LinkedListNode object. This means that, when performing an addition operation, you can get the returned value and do what you want with it.

The class implements the IEnumerable interface. This makes it possible to use foreach to get to access each node. This can be done as follows:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    LinkedList<double> numbers = new LinkedList<double>();
        
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    
    numbers.AddFirst(number);

    foreach (double nbr in numbers)
            MessageBox.Show(nbr.ToString());
}

ApplicationTopic Applied: Getting Each Node of a Linked List

  1. Double-click an unoccupied area of the Altair Realtors form
  2. Change the file as follows:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.IO;
    using System.Windows.Forms;
    using System.Runtime.Serialization.Formatters.Binary;
    
    namespace AltairRealtors1
    {
        public partial class AltairRealtors : Form
        {
            ListViewItem lviSelected;
            LinkedList<RealEstateProperty> properties;
    
            public AltairRealtors()
            {
                InitializeComponent();
            }
    
            private void ShowProperties()
            {
                BinaryFormatter bfmProperty = new BinaryFormatter();
                string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\properties.ars";
    
                // Make sure the file exists
                if (File.Exists(strFileName) == true)
                {
                    // if so, create a file stream
                    using (FileStream stmProperties = new FileStream(strFileName,
                                                              FileMode.Open,
                                                              FileAccess.Read))
                    {
                        // If some properties were created already,
                        // get them and store them in the collection
                        properties = (LinkedList<RealEstateProperty>)bfmProperty.Deserialize(stmProperties);
    
                        // First, empty the list view
                        lvwProperties.Items.Clear();
                        ListViewItem lviProperty = null;
    
                        // Visit each property in the collection and add it to the list view
                        foreach (RealEstateProperty house in properties)
                        {
                            if (house.PropertyType.Equals("Condominium"))
                                lviProperty = new ListViewItem(house.PropertyNumber, lvwProperties.Groups[0]);
                            else if (house.PropertyType.Equals("Townhouse"))
                                lviProperty = new ListViewItem(house.PropertyNumber, lvwProperties.Groups[1]);
                            else // if (house.PropertyType.Equals("Single Family"))
                                lviProperty = new ListViewItem(house.PropertyNumber, lvwProperties.Groups[2]);
    
                            lviProperty.SubItems.Add(house.City);
                            lviProperty.SubItems.Add(house.Stories.ToString());
                            lviProperty.SubItems.Add(house.YearBuilt.ToString());
                            lviProperty.SubItems.Add(house.Bedrooms.ToString());
                            lviProperty.SubItems.Add(house.Bathrooms.ToString("F"));
                            lviProperty.SubItems.Add(house.Condition);
                            lviProperty.SubItems.Add(house.SaleStatus);
                            lviProperty.SubItems.Add(house.MarketValue.ToString());
                            lvwProperties.Items.Add(lviProperty);
                        }
    
                    } // Close the file stream
                }
            }
    
            private void AltairRealtors_Load(object sender, EventArgs e)
            {
                Directory.CreateDirectory("C:\\Microsoft Visual C# Application Design\\Altair Realtors");
                properties = new LinkedList<RealEstateProperty>();
                ShowProperties();
                lviSelected = new ListViewItem();
            }
        }
    }

Navigating Among the Nodes

 

The First and the Last Nodes

As mentioned already, a linked list has a first and a last nodes (some people or documentations call them the head and the tail). To identify the first node, the LinkedList class is equippped with a read-only property named First. Its syntax is:

public LinkedListNode<T> First { get; }

The last node is represented by a read-only property of the same name and that, too, is a LinkedListNode object:

public LinkedListNode<T> Last { get; }

Here are examples of accessing these properties:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    LinkedList<double> numbers = new LinkedList<double>();

    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(2222.06);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddFirst(number);

    MessageBox.Show("The value of the first node is " + numbers.First.Value);
    MessageBox.Show("The value of the last node is " + numbers.Last.Value);
}

The Next and Previous Nodes

To access a node that is next to an existing node, you must first know what node is used as reference. To let you access the next node, the LinkedListNode class is equipped with a read-only property named Next:

public LinkedListNode<T> Next { get; }

To let you access the node previous to an existing one, the LinkedListNode class is equipped with the read-only Previous property:

public LinkedListNode Previous { get; }

Remember that in both cases, you need a node as reference.

Creating Nodes

 

Adding the First Node

When dealing with a linked list, you have many options on how to add a new node. As mentioned already, a linked list has a first node, a last node, and one or more nodes between them. All nodes have and use some references with regards to the node(s) close to them. Based on this, when adding a new node, you have to specify whether you want it as the first node, the last node, the node before a certain node, or the node after a certain one. The LinkedList class easily supports all these operations with very little effort on your part.

We saw that you could call the AddFirst() method to add a new node. In reality, there is no such a thing as simply adding a new node to a linked list. When a linked list has just been created and it is empty, it holds a reference to a null node. There is nothing you can do with that node and you don't need to do anything with it. To start adding nodes, you have the option of setting it as the first or the last item. This would not make any difference because there is no other node in the list.

After adding a node, it becomes a reference that new nodes can use. If you call the AddFirst() method, the new node would be added before any existing node in the collection.

ApplicationTopic Applied: Adding a Node to a Linked List

  1. To create a new form, on the main menu, click PROJECT -> Add Windows Form...
  2. Set the Name to PropertyEditor
  3. Click Add
  4. In the Dialogs section of the Toolbox, click OpenFileDialog
  5. Click the form
  6. In the Properties window, change its characteristics as follows:
    (Name):        dlgPicture
    DefaultExt:  jpg
    Filter:           JPEG Files (*.jpg,*.jpeg)|*.jpg
    Title:            Select House Picture
  7. Design the form as follows:
     
    Altair Realtors - Property Editor
    Control (Name) DropDownStyle Text Items Modifiers Other Properties
    Label Label     Property Type:      
    ComboBox ComboBox cbxPropertyTypes DropDownList   Unknown
    Townhouse
    Single Family
    Condominium
    Public  
    Label Label     Property #:      
    TextBox Text Box txtPropertyNumber       Public  
    Label Label     Address:      
    TextBox Text Box txtAddress       Public  
    Label Label     City:      
    TextBox Text Box txtCity       Public  
    Label Label     State:      
    ComboBox ComboBox cbxStates DropDownList   AL, AK, AZ, AR, CA, CO, CT, DE, DC, FL, GA, HI, ID, IL, IN, IA, KS, KY, LA, ME, MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY, NC, ND, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA, WV, WI, WY Public  
    Label Label     ZIP Code:      
    TextBox Text Box txtZIPCode       Public  
    Label Label     Stories:      
    TextBox Text Box txtStories       Public  
    Label Label     Year Built:      
    TextBox Text Box txtYearBuilt       Public  
    Label Label     Condition:      
    ComboBox ComboBox cbxConditions DropDownList    Excellent
    Good Shape
    Needs Fixing
    Public  
    Label Label     Bedrooms:      
    TextBox Text Box txtBedrooms   0   Public  
    Label Label     Bathrooms:      
    TextBox Text Box txtBathrooms   0.00   Public  
    Label Label     Market Value:      
    TextBox Text Box txtMarketValue   0.00   Public  
    Label Label     Sale Status:      
    ComboBox ComboBox cbxSaleStatus DropDownList   Sold
    Available
    Unspecified
    Public  
    Button btnPicture   Picture...      
    PictureBox PictureBox pbxProperty         BorderStyle: FixedSingle
    SizeMode: Zoom
    Button btnOK   OK     DialogResult: OK
    Button btnCancel   Cancel     DialogResult: Cancel
    Form
    FormBorderStyle: FixedDialog
    Text: Altair Realtors - Property Editor
    StartPosition: CenterScreen
    AcceptButton: btnOK
    CancelButton: btnCancel
    MaximizeBox: False
    MinimizeBox: False
    ShowInTaskBar: False
  8. Double-click an unoccupied area of the form
  9. Return to the form and double-click the Picture button
  10. Change the file as follows:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace AltairRealtors1
    {
        public partial class PropertyEditor : Form
        {
            public bool pictureChanged;
            public string pictureFile;
    
            public PropertyEditor()
            {
                InitializeComponent();
            }
    
            private void PropertyEditor_Load(object sender, EventArgs e)
            {
                pictureChanged = false;
                pictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg";
            }
    
            private void btnPicture_Click(object sender, EventArgs e)
            {
                if (dlgPicture.ShowDialog() == DialogResult.OK)
                {
                    pbxProperty.Image = Image.FromFile(dlgPicture.FileName);
                    pictureFile = dlgPicture.FileName;
                    pictureChanged = true;
                }
            }
        }
    }
  11. Display the Altair Realtors form and, on the form, double-click the New Real Estale Property button
  12. Implement its event as follows:
    private void btnNewProperty_Click(object sender, EventArgs e)
    {
        PropertyEditor editor = new PropertyEditor();
        BinaryFormatter bfmProperty = new BinaryFormatter();
    
        Random rndNumber = new Random(DateTime.Now.Millisecond);
        int number1 = rndNumber.Next(100, 999);
        int number2 = rndNumber.Next(100, 999);
        string propNumber = number1 + "-" + number2;
    
        editor.txtPropertyNumber.Text = propNumber;
    
        // Get a reference to the file that holds the properties
        string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\properties.ars";
    
        // First check if the file was previously created
        if (File.Exists(strFileName) == true)
        {
            // If the list of properties exists already,
            // get it and store it in a file stream
            using (FileStream stmProperties = new FileStream(strFileName,
                                                        FileMode.Open,
                                                        FileAccess.Read))
            {
                // Store the list of properties in the collection
                properties = (LinkedList<RealEstateProperty>)bfmProperty.Deserialize(stmProperties);
            } // Close the file stream
        }
    
        if (editor.ShowDialog() == DialogResult.OK)
        {
            RealEstateProperty prop = new RealEstateProperty();
    
            prop.PropertyNumber = editor.txtPropertyNumber.Text;
            prop.PropertyType = editor.cbxPropertyTypes.Text;
            prop.Address = editor.txtAddress.Text;
            prop.City = editor.txtCity.Text;
            prop.State = editor.cbxStates.Text;
            prop.ZIPCode = editor.txtZIPCode.Text;
            prop.Stories = short.Parse(editor.txtStories.Text);
            prop.YearBuilt = int.Parse(editor.txtYearBuilt.Text);
            prop.Bedrooms = short.Parse(editor.txtBedrooms.Text);
            prop.Bathrooms = float.Parse(editor.txtBathrooms.Text);
            prop.Condition = editor.cbxConditions.Text;
            prop.SaleStatus = editor.cbxSaleStatus.Text;
            prop.MarketValue = double.Parse(editor.txtMarketValue.Text);
            if (!editor.pictureFile.Equals(""))
            {
                FileInfo flePicture = new FileInfo(editor.pictureFile);
                flePicture.CopyTo("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" +
                                  editor.txtPropertyNumber.Text + flePicture.Extension, true);
                prop.PictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" +
                                    editor.txtPropertyNumber.Text + flePicture.Extension;
            }
            else
                prop.PictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg";
    
            // Add the property in the collection
            properties.AddFirst(prop);
    
            // Create a file stream to hold the list of properties
            using (FileStream stmProperties = new FileStream(strFileName,
                                                             FileMode.Create,
                                                             FileAccess.Write))
            {
                // Serialize the list of properties
                bfmProperty.Serialize(stmProperties, properties);
            } // Close the file stream
    
            // Show the list of properties
            ShowProperties();
        }
    }
  13. Return to the Altair Realtors form and click the list view
  14. In the Properties window, click Events and double-click ItemSelectionChanged
  15. Implement the event as follows:
    private void lvwProperties_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
    {
        RealEstateProperty currentProperty = new RealEstateProperty();
        string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" + e.Item.SubItems[0].Text + ".jpg";
    
        if (File.Exists(strFileName))
            pbxProperty.Image = Image.FromFile(strFileName);
        else
            pbxProperty.Image = Image.FromFile("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg");
    }
  16. Press Ctrl + F5 to execute
  17. Click the New Real Estate Property button and create a property as follows:
     
    Property Type Address City State ZIP Code Stories Year Built Condition Bedrooms Bathrooms Market Value Status
    Single Family 4288 Lucow Drive Rockville MD 20856 2 1988 Excellent 3 2.5 665580 Available

    Altair Realtors

  18. Click OK
  19. Copy the following picture and paste (or save) it in the Altair Realtors folder (or the folder that contains the file for the houses of this project):

    Default property

  20. Create the following properties
     
    Property Type Address City State ZIP Code Stories Year Built Condition Bedrooms Bathrooms Market Value Status
    Townhouse 719 Beanson Road Arlington VA 22201 4 1995 Good Shape 4 3.5 580795 Sold
    Condominium 6662 16th Street NW Washington DC 20012 6 1984 Good Shape 1 1 325775 Available

    Altair Realtors

  21. Close the form and return to your programming environment
  22. On the Altair Realtors form, click the list view
  23. In the Events section of the Properties window, double-click DoubleClick
  24. Implement its event as follows:
    private void lvwProperties_DoubleClick(object sender, EventArgs e)
    {
        PropertyEditor editor = new PropertyEditor();
        RealEstateProperty house = new RealEstateProperty();
        BinaryFormatter bfmProperties = new BinaryFormatter();
        string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\properties.ars";
    
        if ((lvwProperties.SelectedItems.Count == 0) || (lvwProperties.SelectedItems.Count > 1))
            return;
    
        using (FileStream stmProperties = new FileStream(strFileName,
                                                         FileMode.Open,
                                                         FileAccess.Read))
        {
            properties = (LinkedList<RealEstateProperty>)bfmProperties.Deserialize(stmProperties);
        }
    
        // Get the property that the user double-clicked
        ListViewItem lviProperty = lvwProperties.SelectedItems[0];
        foreach (RealEstateProperty prop in properties)
            if (prop.PropertyNumber == lviProperty.Text)
                house = prop;
    
        // Prepare to fill the editor with the values of the property the user double-clicked
        editor.txtPropertyNumber.Text = house.PropertyNumber;
        editor.cbxPropertyTypes.Text = house.PropertyType;
        editor.txtAddress.Text = house.Address;
        editor.txtCity.Text = house.City;
        editor.cbxStates.Text = house.State;
        editor.txtZIPCode.Text = house.ZIPCode;
        editor.txtStories.Text = house.Stories.ToString();
        editor.txtYearBuilt.Text = house.YearBuilt.ToString();
        editor.txtBedrooms.Text = house.Bedrooms.ToString();
        editor.txtBathrooms.Text = house.Bathrooms.ToString("F");
        editor.cbxConditions.Text = house.Condition;
        editor.cbxSaleStatus.Text = house.SaleStatus;
        editor.txtMarketValue.Text = house.MarketValue.ToString("F");
        
        string strPictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" + house.PropertyNumber + ".jpg";
    
        if (File.Exists(strPictureFile))
            editor.pbxProperty.Image = Image.FromFile(strPictureFile);
        else
            editor.pbxProperty.Image = Image.FromFile("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg");
    
        // Disable the property number so the user cannot change it
        editor.txtPropertyNumber.Enabled = false;
    
        editor.ShowDialog();
    
        // Show the list of properties
        ShowProperties();
    }
  25. Press Ctrl + F5 to execute the application
  26. Double-click one of the records in the list view
  27. Close the forms and return to your programming environment

Adding the Last Node

By contrast, you can call a method named AddLast. It is overloaded with versions whose syntaxes are:

public LinkedListNode<T> AddLast(T value);
public void AddLast(LinkedListNode<T> node);

When you call this method, the value or node you pass will be added as the last item in the list. Here is an example:

using System;
using System.Windows.Forms;
using System.Collections.Generic;

public class LinkedListExample : Form
{
    Button btnLinkedList;
    ListBox lbxLinkedList;

    public LinkedListExample()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        btnLinkedList = new Button();
        btnLinkedList.Location = new System.Drawing.Point(12, 12);
        btnLinkedList.Text = "Linked List";
        btnLinkedList.Click += new EventHandler(btnLinkedListClicked);

        lbxLinkedList = new ListBox();
        lbxLinkedList.Location = new System.Drawing.Point(12, 40);
        lbxLinkedList.Height = 140;

        Controls.Add(btnLinkedList);
        Controls.Add(lbxLinkedList);
        Text = "Linked List";
        StartPosition = FormStartPosition.CenterScreen;
    }

    private void btnLinkedListClicked(object sender, EventArgs e)
    {
        List<double> values = new List<double>();
        values.Add(84.597);
        values.Add(6.47);
        values.Add(2747.06);
        values.Add(282.924);

        LinkedList<double> numbers = new LinkedList<double>(values);
        LinkedListNode<double> number = new LinkedListNode<double>(148.24);
        numbers.AddFirst(number);

        number = new LinkedListNode<double>(35.75);
        numbers.AddFirst(number);

        numbers.AddLast(2747.06);

        number = new LinkedListNode<double>(2222.06);
        numbers.AddFirst(number);

        number = new LinkedListNode<double>(4.19);
        numbers.AddFirst(number);

        number = new LinkedListNode<double>(66.18);
        numbers.AddFirst(number);

        foreach (double dbl in numbers)
            lbxLinkedList.Items.Add(dbl);
    }
}

public class Exercise
{
    public static int Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new LinkedListExample());
        return 0;
    }
}

Linked List

 
 
 

Nodes Maintenance in a Linked List

 

Inserting a Node Before a Referenced One

A linked list supports the concept of inserting a node but not exactly like traditional collections do it. With a linked list, you must add a node before or after an existing node used as reference.

Behind the scenes, before inserting a node, you must identify the position where you want to put it. That is, you must identify what node you will use as reference:

Inserting a New node Before a Node

In this case, you want to insert a new node before the Other Node. Behind the scenes, the reference between the two existing nodes must be brocken. Then the new node points to the Other Node as its next and the Other Node points at the New Node as its previous:

Inserting a New node Before a Node

After the new node has been added, it must point to the previous node (Some Node in our example) as its previous item. The previous node (Some Node in our example) must now point to the new node as its next item:

Inserting a New node Before a Node

As you may imagine, to insert a node, you must provide two pieces of information: a reference to the node that will succeed the new node, and the new node (or its value). If the referenced node is the first item of the list, the new node would become the new first object.

To assist you with this operation, the LinkedList class provides a method named AddBefore. This method is overloaded with two versions whose syntaxes are:

public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode);
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value);

In both cases, you pass a first argument as an existing node. In the first case, you must pass the LinkedListNode object that will be inserted the node. Here is an example:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number);

    numbers.AddLast(2747.06);

    LinkedListNode<double> number222206 = new LinkedListNode<double>(2222.06);
    numbers.AddLast(number222206);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddBefore(number222206, number);

    number = new LinkedListNode<double>(275.775);
    numbers.AddLast(number);

    foreach (double dbl in numbers)
        lbxLinkedList.Items.Add(dbl);
}

Linked List

In the second version, you directly pass the value to be positioned before node.

Inserting a Node After a Referenced One

Instead of inserting a node before an existing one, you can add it after one. The approach is logically the same as inserting a node before another, except that the sequence is reversed. First identify the node that will be used as reference. Start the process to add the new node after that one. Behind the scenes, the referenced node will point to the new node as its next and the new node will point to the existing node as its previous:

Inserting a New node After an Existing Node

After the new node as been added, it will point to the node after it as its next. The other node will point to the new node as its previous:

Inserting a New node After an Existing Node

If the new node is added after the last node, the new node will become the new last node.

To let you insert a node after an existing node, the LinkedList class is equipped with a method named AddAfter. It comes in two versions and their syntaxes are:

public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode);
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value);

The arguments follow the same description as the AddBefore() method, only in reverse. Here is an example:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    LinkedListNode<double> number3575 = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number3575);

    numbers.AddLast(2747.06);

    LinkedListNode<double> number222206 = new LinkedListNode<double>(2222.06);
    numbers.AddLast(number222206);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddBefore(number222206, number);

    number = new LinkedListNode<double>(275.775);
    numbers.AddAfter(number3575, number);

    foreach (double dbl in numbers)
        lbxLinkedList.Items.Add(dbl);
}

Linked List

ApplicationTopic Applied: Inserting Nodes

  1. Display the Altair Realtors - Properties Listing form
  2. In the Menus & Toolbars section of the Toolbox, click ContextMenuStrip and click the form
  3. Click the menu items as follows:
     
    (Name) Enabled Text
    mnuNewProperty   New Property...
    mnuEditProperty False Edit Property...
    mnuInsertBefore False Insert Property...
    mnuInsertAfter False Insert After
  4. Under the form, click the context menu strip
  5. In the Properties window, change its name to cmsProperties
  6. On the form, click the list view
  7. In the Properties window, set its ContextMenuStrip to cmsProperties
  8. Under the form, click cmsProperties
  9. Under ContextMenuStrip, double-click New Property...
  10. Implement the event as follows:
    private void mnuNewProperty_Click(object sender, EventArgs e)
    {
        btnNewProperty_Click(sender, e);
    }
  11. Locate the ItemSelectionChanged event and change its implementation as follows:
    private void lvwProperties_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
    {
        RealEstateProperty currentProperty = new RealEstateProperty();
        string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" + e.Item.SubItems[0].Text + ".jpg";
    
        if (lvwProperties.SelectedItems.Count == 1)
            lviSelected = lvwProperties.SelectedItems[0];
    
        if (File.Exists(strFileName))
            pbxProperty.Image = Image.FromFile(strFileName);
        else
            pbxProperty.Image = Image.FromFile("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg");
    
        if (lvwProperties.SelectedItems.Count == 1)
        {
            mnuInsertBefore.Enabled = true;
            mnuEditProperty.Enabled = true;
            mnuInsertAfter.Enabled = true;
        }
        else
        {
            mnuInsertBefore.Enabled = false;
            mnuEditProperty.Enabled = false;
            mnuInsertAfter.Enabled = false;
        }
    }
  12. Return to the form and, under the form, click cmsProperties.
    On the form, double-click Edit properties
  13. Implement its event as follows:
    private void mnuEditProperty_Click(object sender, EventArgs e)
    {
        lvwProperties_DoubleClick(sender, e);
    }
  14. Return to the form and, on the form, double-click Insert Before...
  15. Implement the event as follows:
    private void mnuInsertBefore_Click(object sender, EventArgs e)
    {
        PropertyEditor editor = new PropertyEditor();
        RealEstateProperty rep = new RealEstateProperty();
        BinaryFormatter bfmProperties = new BinaryFormatter();
        string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\properties.ars";
    
        if (File.Exists(strFileName) == true)
        {
            using (FileStream stmProperties = new FileStream(strFileName,
                                                        FileMode.Open,
                                                        FileAccess.Read))
            {
                properties = (LinkedList<RealEstateProperty>)bfmProperties.Deserialize(stmProperties);
            }
        }
    
        string strPropertyNumber = lvwProperties.SelectedItems[0].Text;
        rep.PropertyNumber = lvwProperties.SelectedItems[0].Text;
    
        Random rndNumber = new Random(DateTime.Now.Millisecond);
        int number1 = rndNumber.Next(100, 999);
        int number2 = rndNumber.Next(100, 999);
        string propNumber = number1 + "-" + number2;
    
        editor.txtPropertyNumber.Text = propNumber;
        editor.cbxPropertyTypes.Text = lvwProperties.SelectedItems[0].Group.Header;
        editor.cbxPropertyTypes.Enabled = false;
    
        LinkedListNode<RealEstateProperty> nodProperty = properties.Find(rep);
    
        if (nodProperty != null)
        {
            if (editor.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                RealEstateProperty prop = new RealEstateProperty();
    
                prop.PropertyNumber = editor.txtPropertyNumber.Text;
                prop.PropertyType = editor.cbxPropertyTypes.Text;
                prop.Address = editor.txtAddress.Text;
                prop.City = editor.txtCity.Text;
                prop.State = editor.cbxStates.Text;
                prop.ZIPCode = editor.txtZIPCode.Text;
                prop.Stories = short.Parse(editor.txtStories.Text);
                prop.YearBuilt = int.Parse(editor.txtYearBuilt.Text);
                prop.Bedrooms = short.Parse(editor.txtBedrooms.Text);
                prop.Bathrooms = float.Parse(editor.txtBathrooms.Text);
                prop.Condition = editor.cbxConditions.Text;
                prop.SaleStatus = editor.cbxSaleStatus.Text;
                prop.MarketValue = double.Parse(editor.txtMarketValue.Text);
                if (!editor.pictureFile.Equals(""))
                {
                    FileInfo flePicture = new FileInfo(editor.pictureFile);
                    flePicture.CopyTo("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" +
                                        editor.txtPropertyNumber.Text +
                                        flePicture.Extension);
                    prop.PictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" +
                                        editor.txtPropertyNumber.Text +
                                        flePicture.Extension;
                }
                else
                    prop.PictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg";
    
                // Insert the property before the currently selected node
                properties.AddBefore(nodProperty, prop);
    
    		    // Create a file stream to hold the list of properties
                using (FileStream stmProperties = new FileStream(strFileName,
                                                            FileMode.Create,
                                                            FileAccess.Write))
                {
                    bfmProperties.Serialize(stmProperties, properties);
                }
    
                // Show the list of properties
                ShowProperties();
            }
        }
    }
  16. Return to the form and, on the form, double-click Insert After...
  17. Implement the event as follows:
    private void mnuInsertAfter_Click(object sender, EventArgs e)
    {
        PropertyEditor editor = new PropertyEditor();
        RealEstateProperty rep = new RealEstateProperty();
        BinaryFormatter bfmProperties = new BinaryFormatter();
        string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\properties.ars";
    
        if (File.Exists(strFileName) == true)
        {
            using (FileStream stmProperties = new FileStream(strFileName,
                                                      FileMode.Open,
                                                      FileAccess.Read))
            {
                properties = (LinkedList<RealEstateProperty>)bfmProperties.Deserialize(stmProperties);
            }
        }
    
        string strPropertyNumber = lvwProperties.SelectedItems[0].Text;
        rep.PropertyNumber = lvwProperties.SelectedItems[0].Text;
    
        Random rndNumber = new Random(DateTime.Now.Millisecond);
        int number1 = rndNumber.Next(100, 999);
        int number2 = rndNumber.Next(100, 999);
        string propNumber = number1 + "-" + number2;
    
        editor.txtPropertyNumber.Text = propNumber;
        editor.cbxPropertyTypes.Text = lvwProperties.SelectedItems[0].Group.Header;
        editor.cbxPropertyTypes.Enabled = false;
    
        LinkedListNode<RealEstateProperty> nodProperty = properties.Find(rep);
    
        if (nodProperty != null)
        {
            if (editor.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                RealEstateProperty prop = new RealEstateProperty();
    
                prop.PropertyNumber = editor.txtPropertyNumber.Text;
                prop.PropertyType = editor.cbxPropertyTypes.Text;
                prop.Address = editor.txtAddress.Text;
                prop.City = editor.txtCity.Text;
                prop.State = editor.cbxStates.Text;
                prop.ZIPCode = editor.txtZIPCode.Text;
                prop.Stories = short.Parse(editor.txtStories.Text);
                prop.YearBuilt = int.Parse(editor.txtYearBuilt.Text);
                prop.Bedrooms = short.Parse(editor.txtBedrooms.Text);
                prop.Bathrooms = float.Parse(editor.txtBathrooms.Text);
                prop.Condition = editor.cbxConditions.Text;
                prop.SaleStatus = editor.cbxSaleStatus.Text;
                prop.MarketValue = double.Parse(editor.txtMarketValue.Text);
                if (!editor.pictureFile.Equals(""))
                {
                    FileInfo flePicture = new FileInfo(editor.pictureFile);
                    flePicture.CopyTo("C:\\Altair Realtors1\\" +
                                      editor.txtPropertyNumber.Text +
                                      flePicture.Extension);
                    prop.PictureFile = "C:\\Altair Realtors1\\" +
                                      editor.txtPropertyNumber.Text +
                                      flePicture.Extension;
                }
                else
                    prop.PictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg";
    
                // Insert the property before the currently selected node
                properties.AddAfter(nodProperty, prop);
    
                // Create a file stream to hold the list of properties
                using (FileStream stmProperties = new FileStream(strFileName,
                                                          FileMode.Create,
                                                          FileAccess.Write))
                {
                    bfmProperties.Serialize(stmProperties, properties);
                }
    
                // Show the list of properties
                ShowProperties();
            }
        }
    }
  18. To execute, press Ctrl + F5
  19. Create the following properties (let the application generate the property number) (the new records are in bold):
     
    Property Type Address City State ZIP Code Stories Year Built Condition Bedrooms Bathrooms Market Value Status
    Single Family 4288 Lucow Drive Rockville MD 20856 2 1988 Excellent 3 2.5 665580 Available
    Single Family 10202 Lockwood Ave Silver Spring MD 20906 3 2002 Excellent 5 3.5 675880 Sold
    Single Family 8604 L Street NE Washington DC 20016 2 1988 Excellent 3 2.5 465580 Available
    Single Family 6218 Mandarin Road McLean VA 22101 3 1992 Excellent 5 3.5 785680 Available
    Single Family 508 Capitol Street Alexandria VA 22311 3 2006 Excellent 5 3.5 852500 Sold
    Townhouse 719 Beanson Road Arlington VA 22201 4 1995 Good Shape 4 3.5 580795 Sold
    Townhouse 4220 Melmann Drive Baltimore MD 21206 3 1982 Good Shape 3 1 275970 Available
    Townhouse 2428 Wisconsin Ave Washington DC 20008 2 1975 Good Shape 3 1.5 385600 Sold
    Condominium 6662 16th Street NW Washington DC 20012 6 1984 Good Shape 1 1 325775 Available
    Condominium 2644 Swanson Drive Charleston WV 25301 1 2004 Good Shape 2 2 225450 Available
    Condominium 808D Green Tree Rd Arbovale WV 24915 3 2006 Excellent 1 2 216925 Available
  20. Close the form and return to your programming environment

The Value of a Node

Probably the most important aspect of a node is its value. To support it, the LinkedListNode class has a property named Value:

public T Value { get; set; }

Because this is a read-write property, you can use its write-accessory to specify or change its value. On the other hand, you can access the value of a node using this property.

ApplicationTopic Applied: Using the Value of a Node

  1. To create a new form, on the main menu, click PROJECT -> Add Windows Form...
  2. Set the Name to PropertiesReview
  3. Click Add
  4. Design the form as follows:
     
    Altair Realtors - Properties Review
    Control (Name) DropDownStyle Text Other Properties
    Label Label     Property #:  
    TextBox Text Box txtPropertyNumber      
    Label Label     Property Type:  
    TextBox Text Box txtPropertyType      
    Label Label     Address:  
    TextBox Text Box txtAddress      
    Label Label     City:  
    TextBox Text Box txtCity      
    Label Label     State:  
    TexBox Text Box txtState      
    Label Label     ZIP Code:  
    TextBox Text Box txtZIPCode      
    Label Label     Stories:  
    TextBox Text Box txtStories      
    Label Label     Year Built:  
    TextBox Text Box txtYearBuilt      
    Label Label     Condition:  
    TextBox Text Box txtCondition      
    Label Label     Bedrooms:  
    TextBox Text Box txtBedrooms   0  
    Label Label     Bathrooms:  
    TextBox Text Box txtBathrooms   0.00  
    Label Label     Market Value:  
    TextBox Text Box txtMarketValue   0.00  
    Label Label     Sale Status:  
    TextBox Text Box txtStatus      
    PictureBox PictureBox pbxProperty     Anchor: Top, Bottom, Left, Right
    BorderStyle: FixedSingle
    SizeMode: Zoom
    Button btnClose   Close Anchor: Bottom, Left
    Button btnFirst   First Anchor: Bottom, Right
    Label Label lblRecordNumber   000 of 000 Anchor: Bottom, Right
    Button btnPrevious   Previous Anchor: Bottom, Right
    Button btnLast   Last Anchor: Bottom, Right
  5. Double-click an unoccupied area of the form
  6. Return to the Property Review form and double-click the First button
  7. Change the file as follows:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    
    namespace AltairRealtors1
    {
        public partial class PropertiesReview : Form
        {
            int index;
            LinkedList<RealEstateProperty> properties;
            LinkedListNode<RealEstateProperty> nodCurrent;
    
            public PropertiesReview()
            {
                InitializeComponent();
            }
    
            private void PropertiesReview_Load(object sender, EventArgs e)
            {
                index = 1;
                BinaryFormatter bfmProperty = new BinaryFormatter();
                string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\properties.ars";
    
                if (File.Exists(strFileName) == true)
                {
                    using (FileStream stmProperties = new FileStream(strFileName,
                                                              FileMode.Open,
                                                              FileAccess.Read))
                    {
                        properties = (LinkedList<RealEstateProperty>)bfmProperty.Deserialize(stmProperties);
    
                        btnFirst_Click(sender, e);
                    }
                }
            }
    
            private void btnFirst_Click(object sender, EventArgs e)
            {
                index = 1;
                nodCurrent = properties.First;
    
                txtPropertyNumber.Text = nodCurrent.Value.PropertyNumber;
                txtPropertyType.Text = nodCurrent.Value.PropertyType;
                txtAddress.Text = nodCurrent.Value.Address;
                txtCity.Text = nodCurrent.Value.City;
                txtState.Text = nodCurrent.Value.State;
                txtZIPCode.Text = nodCurrent.Value.ZIPCode;
                txtStories.Text = nodCurrent.Value.Stories.ToString();
                txtYearBuilt.Text = nodCurrent.Value.YearBuilt.ToString();
                txtBedrooms.Text = nodCurrent.Value.Bedrooms.ToString();
                txtBathrooms.Text = nodCurrent.Value.Bathrooms.ToString("F");
                txtCondition.Text = nodCurrent.Value.Condition;
                txtSaleStatus.Text = nodCurrent.Value.SaleStatus;
                txtMarketValue.Text = nodCurrent.Value.MarketValue.ToString("F");
    
                string strPictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" + txtPropertyNumber.Text + ".jpg";
    
                if (File.Exists(strPictureFile))
                    pbxProperty.Image = Image.FromFile(strPictureFile);
                else
                    pbxProperty.Image = Image.FromFile("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg");
    
                lblRecordNumber.Text = "1 of " + properties.Count.ToString();
            }
        }
    }
  8. Return to the Property Review form and double-click the Previous button
  9. Implement its event as follows:
    private void btnPrevious_Click(object sender, EventArgs e)
    {
        index--;
    
        if (index <= 1)
            btnFirst_Click(sender, e);
        else
        {
            nodCurrent = nodCurrent.Previous;
    
            txtPropertyNumber.Text = nodCurrent.Value.PropertyNumber;
            txtPropertyType.Text = nodCurrent.Value.PropertyType;
            txtAddress.Text = nodCurrent.Value.Address;
            txtCity.Text = nodCurrent.Value.City;
            txtState.Text = nodCurrent.Value.State;
            txtZIPCode.Text = nodCurrent.Value.ZIPCode;
            txtStories.Text = nodCurrent.Value.Stories.ToString();
            txtYearBuilt.Text = nodCurrent.Value.YearBuilt.ToString();
            txtBedrooms.Text = nodCurrent.Value.Bedrooms.ToString();
            txtBathrooms.Text = nodCurrent.Value.Bathrooms.ToString("F");
            txtCondition.Text = nodCurrent.Value.Condition;
            txtSaleStatus.Text = nodCurrent.Value.SaleStatus;
            txtMarketValue.Text = nodCurrent.Value.MarketValue.ToString("F");
    
            string strPictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" + txtPropertyNumber.Text + ".jpg";
    
            if (File.Exists(strPictureFile))
                pbxProperty.Image = Image.FromFile(strPictureFile);
            else
                pbxProperty.Image = Image.FromFile("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg");
    
            lblRecordNumber.Text = index.ToString() + " of " + properties.Count.ToString();
        }
    }
  10. Return to the Property Review form and double-click the Next button
  11. Return to the Property Review form and double-click the Last button
  12. Implement both events as follows:
    private void btnNext_Click(object sender, EventArgs e)
    {
        index++;
    
        if (index >= properties.Count)
            btnLast_Click(sender, e);
        else
        {
            nodCurrent = nodCurrent.Next;
    
            txtPropertyNumber.Text = nodCurrent.Value.PropertyNumber;
            txtPropertyType.Text = nodCurrent.Value.PropertyType;
            txtAddress.Text = nodCurrent.Value.Address;
            txtCity.Text = nodCurrent.Value.City;
            txtState.Text = nodCurrent.Value.State;
            txtZIPCode.Text = nodCurrent.Value.ZIPCode;
            txtStories.Text = nodCurrent.Value.Stories.ToString();
            txtYearBuilt.Text = nodCurrent.Value.YearBuilt.ToString();
            txtBedrooms.Text = nodCurrent.Value.Bedrooms.ToString();
            txtBathrooms.Text = nodCurrent.Value.Bathrooms.ToString("F");
            txtCondition.Text = nodCurrent.Value.Condition;
            txtSaleStatus.Text = nodCurrent.Value.SaleStatus;
            txtMarketValue.Text = nodCurrent.Value.MarketValue.ToString("F");
    
            string strPictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" + txtPropertyNumber.Text + ".jpg";
    
            if (File.Exists(strPictureFile))
                pbxProperty.Image = Image.FromFile(strPictureFile);
            else
                pbxProperty.Image = Image.FromFile("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg");
    
            lblRecordNumber.Text = index.ToString() + " of " + properties.Count.ToString();
        }
    }
    
    private void btnLast_Click(object sender, EventArgs e)
    {
        index = properties.Count;
        nodCurrent = properties.Last;
    
        txtPropertyNumber.Text = nodCurrent.Value.PropertyNumber;
        txtPropertyType.Text = nodCurrent.Value.PropertyType;
        txtAddress.Text = nodCurrent.Value.Address;
        txtCity.Text = nodCurrent.Value.City;
        txtState.Text = nodCurrent.Value.State;
        txtZIPCode.Text = nodCurrent.Value.ZIPCode;
        txtStories.Text = nodCurrent.Value.Stories.ToString();
        txtYearBuilt.Text = nodCurrent.Value.YearBuilt.ToString();
        txtBedrooms.Text = nodCurrent.Value.Bedrooms.ToString();
        txtBathrooms.Text = nodCurrent.Value.Bathrooms.ToString("F");
        txtCondition.Text = nodCurrent.Value.Condition;
        txtSaleStatus.Text = nodCurrent.Value.SaleStatus;
        txtMarketValue.Text = nodCurrent.Value.MarketValue.ToString("F");
    
        string strPictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" + nodCurrent.Value.PropertyNumber + ".jpg";
    
        if (File.Exists(strPictureFile))
            pbxProperty.Image = Image.FromFile(strPictureFile);
        else
            pbxProperty.Image = Image.FromFile("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg");
    
        lblRecordNumber.Text = properties.Count.ToString() + " of " + properties.Count.ToString();
    }
  13. Return to the Properties Review form and double-click the Close button
  14. Type Close();
  15. Display the Altair Realtors form
  16. On the right side of the New Real Estate Property button, add a new button and set its characteristics as follows:
    (Name): btnReviewProperties
    Text:     Review Properties...

    Altair Realtors - Property Review

  17. Double-click the Review Properties button and implement its event as follows:
    private void btnReviewProperties_Click(object sender, EventArgs e)
    {
        PropertiesReview pr = new PropertiesReview();
    
        pr.ShowDialog();
    }
  18. Save all

ApplicationTopic Applied: Updating a Node

  1. Change the DoubleClick event of the list view as follows:
    private void lvwProperties_DoubleClick(object sender, EventArgs e)
    {
        PropertyEditor editor = new PropertyEditor();
        RealEstateProperty house = new RealEstateProperty();
        BinaryFormatter bfProperties = new BinaryFormatter();
        string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\properties.ars";
    
        if ((lvwProperties.SelectedItems.Count == 0) || (lvwProperties.SelectedItems.Count > 1))
            return;
    
        using (FileStream stmProperties = new FileStream(strFileName,
                                                    FileMode.Open,
                                                    FileAccess.Read))
        {
            properties = (LinkedList<RealEstateProperty>)bfProperties.Deserialize(stmProperties);
        }
    
        // Get the property that the user double-clicked
        ListViewItem lviProperty = lvwProperties.SelectedItems[0];
        // Get the property number the user double-clicked
        house.PropertyNumber = lviProperty.Text;
    
        // Find the property in the list
        LinkedListNode<RealEstateProperty> nodProperty = properties.Find(house);
    
        // Prepare to fill the editor with the values of the property the user double-clicked
        editor.txtPropertyNumber.Text = nodProperty.Value.PropertyNumber;
        editor.cbxPropertyTypes.Text = nodProperty.Value.PropertyType;
        editor.txtAddress.Text = nodProperty.Value.Address;
        editor.txtCity.Text = nodProperty.Value.City;
        editor.cbxStates.Text = nodProperty.Value.State;
        editor.txtZIPCode.Text = nodProperty.Value.ZIPCode;
        editor.txtStories.Text = nodProperty.Value.Stories.ToString();
        editor.txtYearBuilt.Text = nodProperty.Value.YearBuilt.ToString();
        editor.txtBedrooms.Text = nodProperty.Value.Bedrooms.ToString();
        editor.txtBathrooms.Text = nodProperty.Value.Bathrooms.ToString("F");
        editor.cbxConditions.Text = nodProperty.Value.Condition;
        editor.cbxSaleStatus.Text = nodProperty.Value.SaleStatus;
        editor.txtMarketValue.Text = nodProperty.Value.MarketValue.ToString("F");
        
        string strPictureFile = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" + house.PropertyNumber + ".jpg";
    
        if (File.Exists(strPictureFile))
            editor.pbxProperty.Image = Image.FromFile(strPictureFile);
        else
            editor.pbxProperty.Image = Image.FromFile("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg");
    
        // Disable the property number so the user cannot change it
        editor.txtPropertyNumber.Enabled = false;
    
        // Show the property editor
        if (editor.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            // For each value that has changed in the property, update its nnode
            nodProperty.Value.PropertyType = editor.cbxPropertyTypes.Text;
            nodProperty.Value.Address = editor.txtAddress.Text;
            nodProperty.Value.City = editor.txtCity.Text;
            nodProperty.Value.State = editor.cbxStates.Text;
            nodProperty.Value.ZIPCode = editor.txtZIPCode.Text;
            nodProperty.Value.Stories = short.Parse(editor.txtStories.Text);
            nodProperty.Value.YearBuilt = int.Parse(editor.txtYearBuilt.Text);
            nodProperty.Value.Bedrooms = short.Parse(editor.txtBedrooms.Text);
            nodProperty.Value.Bathrooms = float.Parse(editor.txtBathrooms.Text);
            nodProperty.Value.Condition = editor.cbxConditions.Text;
            nodProperty.Value.SaleStatus = editor.cbxSaleStatus.Text;
            nodProperty.Value.MarketValue = double.Parse(editor.txtMarketValue.Text);
            nodProperty.Value.PictureFile = editor.pictureFile;
    
            using (FileStream stmProperties = new FileStream(strFileName,
                                           FileMode.OpenOrCreate,
                                           FileAccess.ReadWrite))
            {
                bfProperties.Serialize(stmProperties, properties);
            }
        }
    
        // Show the list of properties
        ShowProperties();
    }
  2. Press Ctrl + F5 to execute
  3. Double-click the row in the Townhouse section
  4. Change its year built to 2005
  5. Change its market value to 585985 (If possible, also change its picture)

    Altair Realtors

  6. Click OK

    Altair Realtors

  7. Close the form and return to your programming environment

Deleting Nodes

 

Deleting the First or Last Node

When it comes time to delete a node, you have many options, such as deleting the first or the last node of the list. To let you delete the first node, the LinkedList class provides the RemoveFirst() method. Its syntax is:

public void RemoveFirst();

As you can see, this method takes no argument. When it is called:

  • If the list is empty, the compiler throws an InvalidOperationException exception:
  • If the list contains one node, that node gets deleted
  •  If the list contains more than one node, the first one gets deleted

To delete the last node, you can call the RemoveLast() method whose syntax is:

public void RemoveLast();

This method follows the same logic as the RemoveFirst() method, only in reverse. Here are examples of calling these methods:

using System;
using System.Windows.Forms;
using System.Collections.Generic;

public class LinkedListExample : Form
{
    Button btnLinkedList;
    ListBox lbxLinkedListOriginal;
    ListBox lbxLinkedListOther;

    public LinkedListExample()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        btnLinkedList = new Button();
        btnLinkedList.Location = new System.Drawing.Point(12, 12);
        btnLinkedList.Text = "Linked List";
        btnLinkedList.Click += new EventHandler(btnLinkedListClicked);

        lbxLinkedListOriginal = new ListBox();
        lbxLinkedListOriginal.Location = new System.Drawing.Point(12, 40);
        lbxLinkedListOriginal.Size = new System.Drawing.Size(75, 160);

        lbxLinkedListOther = new ListBox();
        lbxLinkedListOther.Location = new System.Drawing.Point(100, 40);
        lbxLinkedListOther.Size = new System.Drawing.Size(75, 160);

        Controls.Add(btnLinkedList);
        Controls.Add(lbxLinkedListOriginal);
        Controls.Add(lbxLinkedListOther);
        Text = "Linked List";
        StartPosition = FormStartPosition.CenterScreen;
    }

    private void btnLinkedListClicked(object sender, EventArgs e)
    {
        List<double> values = new List<double>();
        values.Add(84.597);
        values.Add(6.47);
        values.Add(2747.06);
        values.Add(282.924);

        LinkedList<double> numbers = new LinkedList<double>(values);
        LinkedListNode<double> number = new LinkedListNode<double>(148.24);
        numbers.AddFirst(number);

        LinkedListNode<double> number3575 = new LinkedListNode<double>(35.75);
        numbers.AddFirst(number3575);

        numbers.AddLast(2747.06);

        LinkedListNode<double> number222206 = new LinkedListNode<double>(2222.06);
        numbers.AddLast(number222206);

        number = new LinkedListNode<double>(4.19);
        numbers.AddFirst(number);

        number = new LinkedListNode<double>(66.18);
        numbers.AddBefore(number222206, number);

        number = new LinkedListNode<double>(275.775);
        numbers.AddAfter(number3575, number);

        foreach (double dbl in numbers)
            lbxLinkedListOriginal.Items.Add(dbl);

        numbers.RemoveFirst();
        numbers.RemoveLast();

        foreach (double dbl in numbers)
            lbxLinkedListOther.Items.Add(dbl);
    }
}

public class Exercise
{
    public static int Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new LinkedListExample());
        return 0;
    }
}

Linked List

Removing a Node by Value

There are two ways you can delete an item inside the collection. This can be done using the Remove() method. It comes in two versions. If you know the exact value of the item you want to remove, you can call the following version of that method:

public bool Remove(T value);

When calling this method, pass the value to delete. The compiler would first look for a node that has that value:

  • If there is a node with that value in the list, it would be deleted
  • If there is no node with that value, nothing would happen (the compiler would not throw an exception)

An alternative is to delete a node based on its reference. To do this, use the following version:

public void Remove(LinkedListNode<T> node);

When calling this method, pass a reference to the node you want to delete. Here is an example:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    LinkedListNode<double> number3575 = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number3575);

    numbers.AddLast(2747.06);

    LinkedListNode<double> number222206 = new LinkedListNode<double>(2222.06);
    numbers.AddLast(number222206);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddBefore(number222206, number);

    LinkedListNode<double> number275775 = new LinkedListNode<double>(275.775);
    numbers.AddAfter(number3575, number275775);

    foreach (double dbl in numbers)
        lbxLinkedListOriginal.Items.Add(dbl);

    numbers.Remove(number275775);

    foreach (double dbl in numbers)
        lbxLinkedListOther.Items.Add(dbl);
}

Linked List

ApplicationTopic Applied: Deleting a Node

  1. Display the Properties Listing form
  2. Under the form, click cmsProperties
  3. Add a new menu item as follows:
     
    (Name) Enabled Text
    mnuNewProperty   New Property...
    mnuEditProperty False Edit Property...
    mnuInsertBefore False Insert Property...
    mnuInsertAfter False Insert After
    mnuDeleteProperty False Delete Property
  4. Double-click the Delete Property menu item
  5. In the file, locate the ItemSelectionChanged event and change its implementation as follows:
    private void lvwProperties_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
    {
        RealEstateProperty currentProperty = new RealEstateProperty();
        string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\" + e.Item.SubItems[0].Text + ".jpg";
    
        if (lvwProperties.SelectedItems.Count == 1)
            lviSelected = lvwProperties.SelectedItems[0];
    
        if (File.Exists(strFileName))
            pbxProperty.Image = Image.FromFile(strFileName);
        else
            pbxProperty.Image = Image.FromFile("C:\\Microsoft Visual C# Application Design\\Altair Realtors\\000-000.jpg");
    
        if (lvwProperties.SelectedItems.Count == 1)
        {
            mnuInsertBefore.Enabled = true;
            mnuEditProperty.Enabled = true;
            mnuInsertAfter.Enabled = true;
            mnuDeleteProperty.Enabled = true;
        }
        else
        {
            mnuInsertBefore.Enabled = false;
            mnuEditProperty.Enabled = false;
            mnuInsertAfter.Enabled = false;
            mnuDeleteProperty.Enabled = false;
        }
    }
  6. Scroll down and implement the new event as follows:
    private void mnuDeleteProperty_Click(object sender, EventArgs e)
    {
        PropertyEditor editor = new PropertyEditor();
        RealEstateProperty rep = new RealEstateProperty();
        BinaryFormatter bfProperties = new BinaryFormatter();
        string strFileName = "C:\\Microsoft Visual C# Application Design\\Altair Realtors\\properties.ars";
    
        // Open the file that holds the properties
        if (File.Exists(strFileName))
        {
            using (FileStream stmProperties = new FileStream(strFileName,
                                                        FileMode.Open,
                                                        FileAccess.Read))
            {
                properties = (LinkedList<RealEstateProperty>)bfProperties.Deserialize(stmProperties);
            }
        }
    
        // Create a real estate property using the property number that the user double-clicked
        string strPropertyNumber = lvwProperties.SelectedItems[0].Text;
        rep.PropertyNumber = lvwProperties.SelectedItems[0].Text;
    
        // Ask the compiler to locate that property
        LinkedListNode<RealEstateProperty> nodProperty = properties.Find(rep);
    
        // Just in case, make sure the property was found
        if (nodProperty != null)
        {
            // Present a warning message to the user
            if (MessageBox.Show("Are you sure you want to delete this property?",
                                "Altair Realtors",
                                MessageBoxButtons.YesNoCancel,
                                MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                // If the user clicks yes, delete the property
                properties.Remove(nodProperty);
    
                // Save the list of properties
                using (FileStream stmProperties = new FileStream(strFileName,
                                                            FileMode.Create,
                                                            FileAccess.Write))
                {
                    bfProperties.Serialize(stmProperties, properties);
                }
            }
        }
    
        // Show the new list of properties
        ShowProperties();
    }
  7. Return to the form and double-click the Close button
  8. Implement it as follows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        Close();
    }
  9. To execute, press Ctrl + F5
  10. Right-click one of the records and click Delete Property
  11. Click No
  12. Right-click another row and click Delete Property
  13. Click Yes
  14. Close the form and return to your programming environment

Clearing a Linked List

Clearing a list consists of deleting all of its item. To do this, you could continuous call one of the versions of the Remove() method. A faster solution is to call the Clear() method. Its syntax is:

public void Clear();
 
 
   
 

Home Copyright © 2014, FunctionX