A linked list is a technique of creating a list with
the ability to add,
delete, or retrieve items. Additional operations can also be provided to a
more elaborate list such as finding an item, deleting an item, etc. |
Before creating a list, you probably should first
decide or define what the list would be made of. As different as they are,
one list can be made of numbers. For example, a list that will be made of numbers can define the
item's class as follows:
class Items
{
double Number;
}
You may want a list that is made of names. Such a list
can be created from a class that includes a string member variable. Another type of list can contain complex objects. For example,
if you are starting a database for a car part dealer, you may want to
create a list that includes information about car parts. The class that
holds information for a part can be created as follows: class CarPart
{
public long PartNumber;
public string PartName;
public double UnitPrice;
};
|
Implementing a Linked List |
|
After deciding what each item of the list would be
made of, you can create a class that would manage the list. This class
would be responsible for all operations that can be performed on the list.
Here is an example: |
using System;
class CarPart
{
public long PartNumber;
public string PartName;
public double UnitPrice;
};
class ListOfParts
{
public ListOfParts()
{
}
}
class Exercise
{
static int Main()
{
ListOfParts Parts = new ListOfParts();
return 0;
}
}
It is commonly a good practice to include in a class'
list a member that can be used to keep track of the number of items in the
list. You can declare such a member variable as public but because it is a
regular member variable, it is also a habit of OOP developers to make
such a member private. If you do this and if you want the value to be
accessed outside, you should then provide a public method that serves as
the entry point. Here is how this can be done: |
using System;
class CarPart
{
public long PartNumber;
public string PartName;
public double UnitPrice;
};
class ListOfParts
{
private int size;
public ListOfParts()
{
size = 0;
}
public int Count
{
get { return size; }
}
}
class Exercise
{
static int Main()
{
ListOfParts Parts = new ListOfParts();
Console.WriteLine("Number of Parts: {0}", Parts.Count);
return 0;
}
}
This would produce:
Number of Parts: 0
The Beginning of a Linked List |
|
If you create an array-based
list, you can start by declaring an array member variable that would
hold the items and each item can be located by an index that is assigned
to it when the item is added to the list. When you do this, you must
provide an estimate of the maximum number of items that will be allowed in
the list. Without good planning, the dimension you specify could be too
high or too low but C# doesn't allow you to declare an array without a
dimension if you are not initializing the array. This means that, when you
create an array-based list, you must also specify the maximum number of
items that the list can hold.
A linked list is a list that can grow or shrink as the
user wishes. This means that, when creating the list, you don't need to
predict the maximum number of items that will be added to the list. To use
this flexibility, the items must be managed through pointers. Because the
list would use a member that defines its item, you can declare a member
variable that is conform to the intended items. When a
list starts, it is empty or at least it must be considered like that, before any item is added to it. To
specify this, you should declare a primary
member variable. Although you can call it anything, it is usually called
Head. This member can be made private if you don't intend to access it
outside of the class. If you want clients of the class to access it, you
can make it public. Although this member is declared as a pointer and it
marks the beginning of the list, you should not allocate memory for it in
the constructor. Its memory would be managed when it is accessed.
Therefore, you can simply initialize is as null. Here is an example: |
class ListOfParts
{
private int size;
public ListOfParts()
{
size = 0;
Head = null;
}
public int Count
{
get { return size; }
}
public CarPart Head;
}
As mentioned already, each member of an array-based
list can be accessed using its index, stored in an item member variable
declared as an array. Because the items of a linked list are not indexed,
you must provide another mechanism to locate an item in the list. The
easiest way to do this is to first locate an item, then ask that item to
provide you with a pointer to the item that succeeds it. If the list is
empty, this information would be provided as null. If the item you first
access is the last in the list, you would also provide nothing. Any
other item in the middle would give you access to the next item in the
list. To support this theory, you must provide a pointer to the next item
in the list as a member variable to the class that holds the item. As a
tradition, this member variable is called Next but you can give it any
name you want. Because this item actually is a complete one, it must be
declared as a self-referencing member that has the same name as its class: |
class CarPart
{
public long PartNumber;
public string PartName;
public double UnitPrice;
public CarPart Next;
}
Operations of a Linked List |
|
The primary operation you can perform on a list is to
add a new item to it, since a list is fundamentally empty when it starts.
In order to indicate that you want to add an item to the list, you can
declare a method that receives an item as argument. For the return type,
you have two main options. Because the main job of this method is to add a
new item, which it hardly fails to do if you implement it right, it can be
defined as void. Alternatively, you can make it return the position of the new
item in the list. Here is an example: |
using System;
class CarPart
{
public long PartNumber;
public string PartName;
public double UnitPrice;
public CarPart Next;
};
class ListOfParts
{
private int size;
public ListOfParts()
{
size = 0;
Head = null;
}
public int Count
{
get { return size; }
}
public CarPart Head;
public int Add(CarPart NewItem)
{
CarPart Sample = new CarPart();
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return size++;
}
}
class Exercise
{
static int Main()
{
ListOfParts Parts = new ListOfParts();
CarPart Part;
Part = new CarPart();
Part.PartNumber = 9743;
Part.PartName = "Air Filter";
Part.UnitPrice = 8.75;
Parts.Add(Part);
Part = new CarPart();
Part.PartNumber = 27487;
Part.PartName = "Clutch Disk";
Part.UnitPrice = 47.15;
Parts.Add(Part);
Part = new CarPart();
Part.PartNumber = 87873;
Part.PartName = "Brake Disk";
Part.UnitPrice = 35.15;
Parts.Add(Part);
Part = new CarPart();
Part.PartNumber = 27644;
Part.PartName = "A/C Filter Drier";
Part.UnitPrice = 55.55;
Parts.Add(Part);
Console.WriteLine("Number of Parts: {0}", Parts.Count);
return 0;
}
}
Number of Parts: 4
Once a list exists, the user can explorer it. One of
the operations performed on items is to locate and retrieve one. To do
this, you can declare a method that takes as argument as index. The
method would examine the argument with regards to the number of items in
the list to make sure the argument's value is in the range of current
items of the list. If the number is too low or too high, the method can
return null or 0. If the number is in the range, the method can return the
item at that position. Here is an example: |
using System;
class CarPart
{
public long PartNumber;
public string PartName;
public double UnitPrice;
public CarPart Next;
};
class ListOfParts
{
private int size;
public ListOfParts()
{
size = 0;
Head = null;
}
public int Count
{
get { return size; }
}
public CarPart Head;
public int Add(CarPart NewItem)
{
CarPart Sample = new CarPart();
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return size++;
}
public CarPart Retrieve(int Position)
{
CarPart Current = Head;
for(int i = 0; i < Position && Current != null; i++)
Current = Current.Next;
return Current;
}
}
class Exercise
{
static int Main()
{
ListOfParts Parts = new ListOfParts();
CarPart Part;
Part = new CarPart();
Part.PartNumber = 9743;
Part.PartName = "Air Filter";
Part.UnitPrice = 8.75;
Parts.Add(Part);
Part = new CarPart();
Part.PartNumber = 27487;
Part.PartName = "Clutch Disk";
Part.UnitPrice = 47.15;
Parts.Add(Part);
Part = new CarPart();
Part.PartNumber = 87873;
Part.PartName = "Brake Disk";
Part.UnitPrice = 35.15;
Parts.Add(Part);
Part = new CarPart();
Part.PartNumber = 27644;
Part.PartName = "A/C Filter Drier";
Part.UnitPrice = 55.55;
Parts.Add(Part);
Console.WriteLine(" -=- Store Inventory -=-");
Console.WriteLine("Number of Parts: {0}", Parts.Count);
for(int i = 0; i < Parts.Count; i++)
{
CarPart part = Parts.Retrieve(i);
Console.WriteLine("\nCar Part Information");
Console.WriteLine("Part #: {0}", part.PartNumber);
Console.WriteLine("Description: {0}", part.PartName);
Console.WriteLine("Unit Price: {0:C}", part.UnitPrice);
}
return 0;
}
}
|
|