Collections.Generic Namespace pdf

6 101 0
Collections.Generic Namespace pdf

Đang tải... (xem toàn văn)

Thông tin tài liệu

Creating a Generic Class The .NET Framework Class Library contains a number of generic classes readily available for you. You can also define your own generic classes, which is what you will do in this section. Before we do this, I will provide a bit of background theory. The Theory of Binary Trees In the following exercises, you will define and use a class that represents a binary tree. This is a very practical exercise because this class happens to be one that is missing from the System.Collections.Generic namespace. A binary tree is a very useful data structure used for a variety of operations, including sorting and searching through data very quickly. There are volumes written on the minutiae of binary trees, but it is not the purpose of this book to cover binary trees in detail. Instead, we will just look at the pertinent details. If you are interested you should consult a book such as The Art of Computer Programming, Volume 3: Sorting and Searching by Donald E. Knuth (Addison-Wesley Professional; 2 nd edition 1998). A binary tree is a recursive (self-referencing) data structure that can either be empty or comprise three elements: some data that is typically referred to as the node and two sub- trees, which are themselves binary trees. The two sub-trees are conventionally called the left sub-tree and the right sub-tree because they are typically depicted to the left and right of the node respectively. Each left sub-tree or right sub-tree is either empty, or contains a node and other sub-trees. In theory, the whole structure can continue ad infinitum. Figure 17-1 shows the structure of a small binary tree. The real power of binary trees becomes evident when you use them for sorting data. If you start with an unordered sequence of objects of the same type, you can use them to construct an ordered binary tree and then walk through the tree to visit each node in an ordered sequence. The algorithm for inserting an item into an ordered binary tree is shown below: If the tree, T, is empty Then Construct a new tree T with the new item I as the node, and empty left and right sub-trees Else Examine the value of the node, N, of the tree, T If the value of N is greater than that of the new item, I Then If the left sub-tree of T is empty Then Construct a new left sub-tree of T with the item I as the node, and empty left and right sub-trees Else Insert I into the left sub-tree of T End If Else If the right sub-tree of T is empty Then Construct a new right sub-tree of T with the item I as the node, and empty left and right sub-trees Else Insert I into the right sub-tree of T End If End If End If Figure 17-1 A binary tree. Notice that this algorithm is recursive, calling itself to insert the item into the left or right sub-tree depending on the value of the item and the current node in the tree. NOTE The definition of the expression greater than depends on the type of data in the item and node. For numeric data, greater than can be a simple arithmetic comparison, for text data it can be a string comparison, but other forms of data must be given their own means of comparing values. This is discussed in more detail when we implement a binary tree in the section “Building a Binary Tree Class Using Generics” later in this chapter. If you start with an empty binary tree and an unordered sequence of objects, you can iterate through the unordered sequence inserting each one into the binary tree by using this algorithm, resulting in an ordered tree. Figure 17-2 shows the steps in the process for constructing a tree from a set of 5 integers. Figure 17-2 Constructing an ordered binary tree. Once you have built an ordered binary tree, you can display its contents in sequence by visiting each node in turn and printing the value found. The algorithm for achieving this task is also recursive: If the left sub-tree is not empty Then Display the contents of the left sub-tree End If Display the value of the node If the right sub-tree is not empty Then Display the contents of the right sub-tree End If Figure 17-3 shows the steps in the process for outputting the tree constructed earlier. Notice that the integers are now displayed in ascending order. Figure 17-3 Printing an ordered binary tree. Building a Binary Tree Class Using Generics In the following exercise, you will use generics to define a binary tree class capable of holding almost any type of data. The only restriction is that the data type must provide a means of comparing values between different instances. The binary tree class is a class that you might find useful in many different applications. Therefore, you will implement it as a class library rather than an application in its own right. You can then reuse this class elsewhere without needing to copy the source code and recompile it. A class library is a set of compiled classes (and other types such as structs and delegates) stored in an assembly. An assembly is a file that usually has the “.dll” suffix. Other projects and applications can make use of the items in a class library by adding a reference to its assembly, and then bringing its namespaces into scope with using statements. You will do this when you test the binary tree class. The System.IComparable and System.IComparable<T> Interfaces If you need to create a class that requires you to be able to compare values according to some natural (or possibly unnatural) ordering, you should implement the IComparable interface. This interface contains a method called CompareTo, which takes a single parameter specifying the object to be compared to the current instance and returns an integer that indicates the result of the comparison as shown in the following table. Value Meaning Less than zero The current instance is less than the value of the parameter Zero The current instance is equal to the value of the parameter. Greater than zero The current instance is greater than the value of the parameter As an example, consider the Circle class that was described in Chapter 7, “Creating and Managing Classes and Objects,” and is reproduced below: class Circle { public Circle(double initialRadius) { radius = initialRadius; } public double Area() { return 3.141593 * radius * radius; } private double radius; } You can make the Circle class comparable by implementing the System.IComparable interface and providing the CompareTo method. In the example shown, the CompareTo method compares Circle objects based on their areas. The area of a circle with a larger area is greater than a circle with a smaller area. class Circle : System.IComparable { public int CompareTo(object obj) { Circle circObj = (Circle)obj; // cast the parameter to its real type if (this.Area() == circObj.Area()) return 0; if (this.Area() > circObj.Area()) return 1; return -1; } } If you examine the System.IComparable interface, you will see that its parameter is defined as an object. However, this approach is not typesafe. To understand why this is so, consider what happens if you try to pass something that is not a Circle to the CompareTo method. The System.IComparable interface requires the use of a cast in order to be able to access the Area method. If the parameter is not a Circle but some other type of object then this cast will fail. However, the System namespace also defines the generic IComparable<T> interface, which contains the following methods: int CompareTo(T other); bool Equals(T other); Notice there is an additional method in this interface, called Equals, which should return true if both instances are equals, false if they are not equals. Also notice that these methods take a type parameter (T) rather than an object, and as such, are much safer than the non-generic version of the interface. The following code shows how you can implement this interface in the Circle class: class Circle : System.IComparable<Circle> { public int CompareTo(Circle other) { if (this.Area() == other.Area()) return 0; if (this.Area() > other.Area()) return 1; return -1; } public bool Equals(Circle other) { return (this.CompareTo(other) == 0); } } The parameters for the CompareTo and Equals method must match the type specified in the interface, IComparable<Circle>. In general, it is preferable to implement the System.IComparable<T> interface rather than System.IComparable. You can also implement both, as many of the types in the .NET Framework do. Create the Tree<T> class 1. Start Visual Studio 2005. 2. Create a new Visual C# project using the Class Library template (on the File menu, point to New, and then click Project). Name the project BinaryTree and set the Location to \Microsoft Press\Visual CSharp Step By Step\Chapter 17. 3. In the Solution Explorer change the name of the file Class1.cs to Tree.cs. 4. In the Code and Text Editor window, change the definition of the Class1 class to Tree<T>. The definition of the Tree<T> class should look like this: public class Tree<T> { }  . Creating a Generic Class The .NET Framework Class Library contains a number of generic classes readily available for you. You can also define your own generic classes, which is. practical exercise because this class happens to be one that is missing from the System .Collections. Generic namespace. A binary tree is a very useful data structure used for a variety of operations,. 17-3 Printing an ordered binary tree. Building a Binary Tree Class Using Generics In the following exercise, you will use generics to define a binary tree class capable of holding almost any type

Ngày đăng: 01/07/2014, 09:20

Tài liệu cùng người dùng

Tài liệu liên quan