1. Trang chủ
  2. » Công Nghệ Thông Tin

Creating a one-to-many Map doc

88 254 0

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 88
Dung lượng 286,12 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Generic BinaryTree class private int counter = 0; // Number of nodes in tree private BinaryTreeNode root = null; // Pointer to root node in this tree public void AddNodeT value... Basi

Trang 1

This code displays the following:

Key: 0 Value: zero :

Key: 1 Value: one :

Key: 2 Value: two :

Key: 3 Value: three : duplicate three : duplicate three :

Console.WriteLine("Contains Key 2: " + myMap.ContainsKey(2));

Console.WriteLine("Contains Key 12: " + myMap.ContainsKey(12));

Console.WriteLine("Contains Value two: " + myMap.ContainsValue("two"));

Console.WriteLine("Contains Value BAR: " + myMap.ContainsValue("BAR"));

// Clear all items from MultiMap

myMap.Clear( );

}

Example 11-5 Testing the MultiMap class (continued)

Trang 2

Key: 5 Value: foo :

Key: 6 Value: foo :

((ArrayList) myMap[3])[0]: three

((ArrayList) myMap[3])[1]: duplicate three

myMap.Count: 6

entry.Key: 2 entry.Value(s): two :

entry.Key: 3 entry.Value(s): three : duplicate three : duplicate three : entry.Key: 4 entry.Value(s):

entry.Key: 5 entry.Value(s): foo :

entry.Key: 6 entry.Value(s): foo :

entry.Key: 10 entry.Value(s): BAR : BAZ :

myMap.ContainsKey(2): True

myMap.ContainsValue(two): True

Contains Key 2: True

Contains Key 12: False

Contains Value two: True

Contains Value BAR: True

Discussion

A one-to-many map, or multimap, allows one object, a key, to be associated, or

mapped, to zero or more objects The MultiMap<T,U>class presented here operates similarly to a Dictionary<T,U> The MultiMap<T,U> class contains a Dictionary<T,List<U>>field calledmapthat containsthe actual mapping of keysto values Several

of theMultiMap<T,U>methodsare delegated to the methodson themap Dictionary<T,List<U>> object.

ADictionary<T,U> operates on a one-to-one principle: only one key may be ated with one value at any time However, if you need to associate multiple values with a single key, you must use the approach used by theMultiMap<T,U>class The privatemapfield associates a key with a singleList<U>of values, which allows multi- ple mappingsof valuesto a single key and mappingsof a single value to multiple keys As an added feature, a key can also be mapped to anull value.

associ-Here’s what happens when key-value pairs are added to aMultiMap<t,U> object:

1 The MultiMap<T,U>.Add method iscalled with a key and value provided as parameters.

2 The Add method checksto see whether key exists in the map Dictionary<T,List<U>> object.

3 If keydoesnot exist, it isadded asa key in the map Dictionary<T, List<U>>

object This key is associated with a newList<U>as the value associated withkey

in thisHashtable.

4 If the key doesexist, thekeyislooked up in the map Dictionary<T, List<U>>

object, and thevalue is added to thekey’sList<U>.

Trang 3

To remove a key using the Remove method, the key and List<U> pair are removed from the mapDictionary<T, List<U>> This allows removal of all values associated with a single key The MultiMap<T,U>.Remove method callsthe RemoveSingleMap

method, which encapsulates this behavior Removal of key “0”, and all values mapped to this key, is performed with the following code:

{

Console.Write("Key: " + entry.Key.ToString( ) + "\tValue: ");

foreach (string str in myMap[entry.Key])

Trang 4

Key: 0 Value: zero :

Key: 1 Value: one :

Key: 2 Value: two :

Key: 3 Value: three : duplicate three : duplicate three :

Key: 4 Value:

Key: 5 Value: foo :

Key: 6 Value: foo :

Two methodsthat allow searching of the MultiMap<T,U>object areContainsKeyand

ContainsValue The ContainsKey method searches for the specified key in the mapDictionary<T, List<U>> TheContainsValuemethod searches for the specified value

in a List<U> in the map Dictionary<T, List<U>> Both methodsreturn trueif the key-value was found orfalse otherwise:

Console.WriteLine("Contains Key 2: " + myMap.ContainsKey(2));

Console.WriteLine("Contains Key 12: " + myMap.ContainsKey(12));

Console.WriteLine("Contains Value two: " + myMap.ContainsValue("two")); Console.WriteLine("Contains Value BAR: " + myMap.ContainsValue("BAR"));Note that theContainsKey andContainsValue methods are both case-sensitive.

Solution

To implement a binary tree of the type described in the Problem statement, each node must be an object that inherits from theIComparable<T>interface Thismeans that every node to be included in the binary tree must implement the CompareTo

method Thismethod will allow one node to determine whether it islessthan, greater than, or equal to another node.

Use theBinaryTree<T>class shown in Example 11-6, which contains all of the nodes

in a binary tree and lets you traverse it.

Trang 5

Example 11-6 Generic BinaryTree class

private int counter = 0; // Number of nodes in tree

private BinaryTreeNode<T> root = null; // Pointer to root node in this tree

public void AddNode(T value)

Trang 6

TheBinaryTreeNode<T> shown in Example 11-7 encapsulates the data and behavior

of a single node in the binary tree.

Example 11-7 Generic BinaryTreeNode class

public class BinaryTreeNode<T>

private T nodeValue = default(T);

private BinaryTreeNode<T> leftNode = null; // leftNode.nodeValue < Value

private BinaryTreeNode<T> rightNode = null; // rightNode.nodeValue >= Value

public int Children

Trang 7

bool isUnique = true;

Example 11-7 Generic BinaryTreeNode class (continued)

Trang 8

Example 11-7 Generic BinaryTreeNode class (continued)

Trang 9

public void RemoveLeftNode( )

Example 11-7 Generic BinaryTreeNode class (continued)

Trang 10

The methods defined in Table 11-3 are of particular interest to using aBinaryTree<T>

wherevalue is the root node for the tree Note that this tree may not be flattened

AddNode method Adds a node to the tree Its syntax is:

AddNode(T value, int id)

wherevalue is the object to be added andid is the node index Use this method ifthe tree will be flattened

AddNode method Adds a node to the tree Its syntax is:

AddNode(T value)

wherevalue is the object to be added Use this method if the tree will not be tened

flat-SearchDepthFirst method Searches for and returns aBinaryTreeNode<T> object in the tree, if one exists

This method searches the depth of the tree first Its syntax is:

SearchDepthFirst(T value)

wherevalue is the object to be found in the tree

Print method Displays the tree in depth-first format Its syntax is:

Print( )Root property Returns theBinaryTreeNode<T> object that is the root of the tree Its syntax is:

RootTreeSize property A read-only property that gets the number of nodes in the tree Its syntax is:

int TreeSize {get;}

Example 11-7 Generic BinaryTreeNode class (continued)

Trang 11

The code in Example 11-8 illustrates the use of the BinaryTree<T> and

BinaryTreeNode<T> classes when creating and using a binary tree.

Table 11-4 Members of the BinaryTreeNode<T> class

Left property A read-only property to retrieve the left child node below this node Its syntax is:

BinaryTreeNode<T> Left {get;}

Right property A read-only property to retrieve the right child node below this node Its syntax is:

BinaryTreeNode<T> Right {get;}

Children property Retrieves the number of child nodes below this node Its syntax is:

Children( )GetValue method Returns theIComparable<T> object that this node contains Its syntax is:

GetValue( )AddNode method Adds a new node recursively to either the left or right side Its syntax is:

AddNode(BinaryTreeNode<T> node)

wherenodeis the node to be added Duplicate nodes may be added using this method

AddUniqueNode method Adds a new node recursively to either the left side or the right side Its syntax is:

AddUniqueNode(BinaryTreeNode<T> node)

wherenode is the node to be added Duplicate nodes may not be added using thismethod A Boolean value is returned:true indicates a successful operation;false

indicates an attempt to add a duplicate node

DepthFirstSearch method Searches for and returns aBinaryTreeNode<T>object in the tree, if one exists This

method searches the depth of the tree first Its syntax is:

DepthFirstSearch(T targetObj)

wheretargetObj is the object to be found in the tree

PrintDepthFirst method Displays the tree in depth-first format Its syntax is:

PrintDepthFirst( )RemoveLeftNode method Removes the left node and any child nodes of this node Its syntax is:

RemoveLeftNode( )RemoveRightNode method Removes the right node and any child nodes of this node Its syntax is:

RemoveRightNode( )

Example 11-8 Using the BinaryTree and Binary TreeNode classes

public static void TestBinaryTree( )

Trang 12

The output for this method is shown here:

Contains Left: NULL

Contains Right: NULL

d

Contains Left: a

Contains Right: f

e

Contains Left: NULL

Contains Right: NULL

Trang 13

f

Contains Left: e

Contains Right: g

g

Contains Left: NULL

Contains Right: NULL

Contains Left: NULL

Contains Right: NULL

d

Contains Left: a

Contains Right: f

e

Contains Left: NULL

Contains Right: NULL

f

Contains Left: e

Contains Right: g

g

Contains Left: NULL

Contains Right: NULL

Contains Left: NULL

Contains Right: NULL

f

Contains Left: e

Contains Right: g

g

Contains Left: NULL

Contains Right: NULL

d

Contains Left: NULL

Contains Right: NULL

Trang 14

Trees are data structures in which each node has exactly one parent and possibly

many children The root of the tree isa single node that branchesout into one or

more child nodes A node isthe part of the tree structure that containsdata and tains the branches (or in more concrete terms, references) to its children node(s).

con-A tree can be used for many things, such as to represent a management hierarchy with the president of the company at the root node and the various vice presidents as child nodes of the president The vice presidents may have managers as child nodes, and so on A tree can be used to make decisions, where each node of the tree con- tains a question, and the answer given depends on which branch is taken to a child

node The tree described in this recipe is called a binary tree A binary tree can have

zero, one, or two child nodesfor every node in the tree A binary tree node can never have more than two child nodes; thisiswhere thistype of tree getsitsname (There

are other types of trees For instance, the n-ary tree can have zero to n nodesfor each

node in the tree This type of tree is defined in Recipe 11.5.)

A binary tree is very useful for storing objects and then efficiently searching for those objects There are definitely more efficient algorithms out there for sorting binary treesthan the one implemented here For example, if you need to store key/value pairs, you can look at using theSortedListor theSortedDictionaryclasses built into the NET Framework For storing large amounts of data (i.e., items numbering in the hundreds of thousands or higher), these two data structures will perform better For storing small numbers of items (i.e., a few hundred or lower), this data structure’s performance will be fine.

The following algorithm is used to store objects in a binary tree:

1 Start at the root node.

2 Is this node free?

a If yes, add the object to this node, and you are done.

b If no, continue.

3 Isthe object to be added to the tree lessthan (less than isdetermined by the

IComparable<T>.CompareTo method of the node being added) the current node?

a If yes, follow the branch to the node on the left side of the current node, and

go to step 2.

b If no, follow the branch to the node of the right side of the current node, and

go to step 2.

Basically, this algorithm states that the node to the left of the current node contains

an object or value less than the current node, and the node to the right of the current node containsan object or value greater than (or equal to, if the binary tree can con- tain duplicates) the current node.

Trang 15

Searching for an object in a tree is easy Just start at the root and ask, “Is the object I

am searching for?” If it is not, then you need to ask “is the object I am searching for lessthan the current node’sobject?” If it is, follow the left branch to the next node in the tree If it isstill not the correct object, continue down the right branch to the next node When you get to the next node, start the process over again.

The binary tree used in this recipe is made up of two classes TheBinaryTree<T>class isnot a part of the actual tree; rather, it actsasa starting point from which you can create a tree, add nodes to it, search the tree for items, and retrieve the root node to perform other actions.

The second class,BinaryTreeNode<T>, isthe heart of the binary tree and representsa single node in the tree This class contains all the members that are required to cre- ate and work with a binary tree.

TheBinaryTreeNode<T>class contains a protected field,nodeValue, which containsan object implementing theIComparable<T>interface Thisstructure allowsyou to per- form searches and add nodes in the correct location in the tree The CompareTo

method of theIComparable<T>interface is used in searching and adding methods to determine whether you need to follow the left or right branch See the AddNode,

AddUniqueNode, and DepthFirstSearch methods—discussed in the following graphs—to see this in action.

para-There are two methodsto add nodesto the tree, AddNode and AddUniqueNode The

AddNode method allowsduplicatesto be introduced to the tree, whereasthe

AddUniqueNode allows only unique nodes to be added.

The DepthFirstSearch method allows the tree to be searched by first checking the current node to see whether it contains the value searched for; if not, recursion is used to check the left or the right node If no matching value is found in any node, this method returnsnull.

It isinteresting to note that even though theBinaryTree<T>class is provided to ate and manage the tree of BinaryTreeNode<T> objects, you can merely use the

cre-BinaryTreeNode<T>class as long as you keep track of the root node yourself The code shown in Example 11-9 creates and manages the tree without the use of the

BinaryTree<T> class.

Example 11-9 Creating and managing a binary tree without using the BinaryTree class

public static void TestManagedTreeWithNoBinaryTreeClass( )

{

// Create the root node

BinaryTreeNode<string> topLevel = new BinaryTreeNode<string>("d");

// Create all nodes that will be added to the tree

BinaryTreeNode<string> one = new BinaryTreeNode<string>("b");

BinaryTreeNode<string> two = new BinaryTreeNode<string>("c");

BinaryTreeNode<string> three = new BinaryTreeNode<string>("a");

Trang 16

The output for this method is shown here:

a

Contains Left: NULL

Contains Right: b

BinaryTreeNode<string> four = new BinaryTreeNode<string>("e");

BinaryTreeNode<string> five = new BinaryTreeNode<string>("f");

BinaryTreeNode<string> six = new BinaryTreeNode<string>("g");

// Add nodes to tree through the root

Trang 17

b

Contains Left: NULL

Contains Right: c

c

Contains Left: NULL

Contains Right: NULL

d

Contains Left: a

Contains Right: f

e

Contains Left: NULL

Contains Right: NULL

f

Contains Left: e

Contains Right: g

g

Contains Left: NULL

Contains Right: NULL

Contains Left: NULL

Contains Right: NULL

Contains Left: NULL

Contains Right: NULL

f

Contains Left: e

Contains Right: g

g

Contains Left: NULL

Contains Right: NULL

d

Contains Left: NULL

Contains Right: NULL

Trang 18

// The root node of the tree

private NTreeNode<T> root = null;

// The maximum number of child nodes that a parent node may contain

private int maxChildren = 0;

public void AddRoot(NTreeNode<T> node)

Trang 19

The methods defined in Table 11-5 are of particular interest to using an NTree<T>

object.

TheNTreeNodeFactory<T>class is used to create nodes for the n-ary tree These nodes

are defined in the class NTreeNode<U>, which is nested inside of the

NTreeNodeFactory<T> class You are not able to create an NTreeNode<U>without the use of this factory class, as shown in Example 11-11.

Table 11-5 Members of the NTree<T> class

int MaxChildren {get;}

The value this property returns is set in the constructor

AddRoot method Adds a node to the tree Its syntax is:

AddRoot(NTreeNodeFactory<T>.NTreeNode<U> node)

wherenode is the node to be added as a child to the current node

Example 11-11 Using the class to create the nodes for an n-ary tree

public class NTreeNodeFactory<T>

private int maxChildren = 0;

public int MaxChildren

// Nested Node class

public class NTreeNode<U>

where U : IComparable<U>

{

Trang 20

public NTreeNode(U value, int maxChildren)

protected U nodeValue = default(U);

protected NTreeNode<U>[] childNodes = null;

public int CountChildren

public NTreeNode<U>[] Children

Example 11-11 Using the class to create the nodes for an n-ary tree (continued)

Trang 21

{

get {return (childNodes);} }

public NTreeNode<U> GetChild(int index) {

return (childNodes[index]); }

public U Value( ) {

return (nodeValue); }

public void AddNode(NTreeNode<U> node) {

int numOfNonNullNodes = CountImmediateChildren; if (numOfNonNullNodes < childNodes.Length) {

childNodes[numOfNonNullNodes] = node; }

else {

throw (new Exception("Cannot add more children to this node.")); }

}

public NTreeNode<U> DepthFirstSearch(U targetObj) {

NTreeNode<U> retObj = default(NTreeNode<U>); if (targetObj.CompareTo(nodeValue) == 0) {

retObj = this; }

else {

for (int index=0; index<=childNodes.GetUpperBound(0); index++) {

if (childNodes[index] != null) {

retObj = childNodes[index].DepthFirstSearch(targetObj); if (retObj != null) {

break; }

}

}

}

return (retObj); }

Example 11-11 Using the class to create the nodes for an n-ary tree (continued)

Trang 22

public NTreeNode<U> BreadthFirstSearch(U targetObj)

// Get next node in queue

NTreeNode<U> currentNode = row.Dequeue( );

// Is this the node we are looking for?

if (targetObj.CompareTo(currentNode.nodeValue) == 0) {

Trang 23

The methods defined in Table 11-6 are of particular interest to using an

List<U> tempList = new List<U>( );

for (int index = 0; index < childNodes.Length; index++)

throw (new ArgumentOutOfRangeException("index", index,

"Array index out of bounds."));

Trang 24

The methods defined in Table 11-7 are of particular interest to using the nested

NTreeNode<U> object.

Table 11-6 Members of the NTreeNodeFactory<T> class

Constructor Creates a newNTreeNodeFactory<T> object that will createNTreeNode<U> objects

with the same number ofMaxChildren that theNTree<T> object passed in supports Itssyntax is:

NTreeNodeFactory(NTree<T> root)

whereroot is anNTree<T> object

MaxChildren property Read-only property that returns the maximum number of children that theNTree<T> object

supports Its syntax is:

int MaxChildren {get;}

CreateNode method Overloaded method that returns a newNTreeNode object Its syntax is:

CreateNode( )

CreateNode(IComparable value)

wherevalue is theIComparable object this new node object will contain

Table 11-7 Members of the NTreeNode<U> class

Constructor Creates a newNTreeNode<U> object from theNTreeNodeFactory<T>

object passed in to it Its syntax is:

NTreeNode(T value, int maxChildren)

wherevalue is anIComparable<T> object andmaxChildren is thetotal number of children allowed by this node

NumOfChildren property Read-only property that returns the total number of children below this node

Its syntax is:

int NumOfChildren {get;}

Children property Read-only property that returns all of the non-null child-node objects in an

array that the current node contains Its syntax is:

NTreeNode<U>[] Children {get;}

CountChildren property Recursively counts the number of non-null child nodes below the current

node and returns this value as an integer Its syntax is:

CountChildrenCountImmediateChildren property Counts only the non-null child nodes contained in the current node Its syn-

tax is:

CountImmediateChildrenGetChild method Uses an index to return theNTreeNode<U> contained by the current node

Its syntax is:

GetChild(int index)

where index is the array index where the child object is stored

Value method Returns an object of type T that the current node contains Its syntax is:

Value( )

Trang 25

The code shown in Example 11-12 illustrates the use of the NTree<T>, NodeFactory<T>, andNTreeNode<U> classes to create and manipulate an n-ary tree.

NTree-AddNode method Adds a new child node to the current node Its syntax is:

AddNode(NTreeNode<U> node)

wherenode is the child node to be added

DepthFirstSearch method Attempts to locate anNTreeNode<U> by theIComparable<T> object

that it contains AnNTreeNode<U> is returned if theIComparable<T>

object is located or anull if it is not Its syntax is:

DepthFirstSearch(IComparable<T> targetObj)

wheretargetObj is theIComparable<T> object to locate in the tree.Note that this search starts with the current node, which may or may not bethe root of the tree The tree traversal is done in a depth-first manner

BreadthFirstSearch method Attempts to locate anNTreeNode<U> by theIComparable<T> object

that it contains AnNTreeNode<U> is returned if theIComparable<T>

object is located or anull if it is not Its syntax is:

BreadthFirstSearch(IComparable<T> targetObj)

wheretargetObj is theIComparable<T> object to locate in the tree.Note that this search starts with the current node, which may or may not bethe root of the tree The tree traversal is done in a breadth-first manner

PrintDepthFirst method Displays the tree structure on the console window starting with the current

node Its syntax is:

PrintDepthFirst( )

This method uses recursion to display each node in the tree

RemoveNode method Removes the child node at the specifiedindex on the current node Its

syn-tax is:

RemoveNode(int index)

whereindex is the array index where the child object is stored Note thatwhen a node is removed, all of its children nodes are removed as well

Example 11-12 Using the NTree<T>, NTreeNodeFactory<T>, and NTreeNode<U> classes

public static void TestNTree( )

{

NTree<string> topLevel = new NTree<string>(3);

NTreeNodeFactory<string> nodeFactory =

new NTreeNodeFactory<string>(topLevel);

NTreeNode<string> one = nodeFactory.CreateNode("One");

NTreeNode<string> two = nodeFactory.CreateNode("Two");

NTreeNode<string> three = nodeFactory.CreateNode("Three");

NTreeNode<string> four = nodeFactory.CreateNode("Four");

NTreeNode<string> five = nodeFactory.CreateNode("Five");

NTreeNode<string> six = nodeFactory.CreateNode("Six");

NTreeNode<string> seven = nodeFactory.CreateNode("Seven");

NTreeNode<string> eight = nodeFactory.CreateNode("Eight");

Table 11-7 Members of the NTreeNode<U> class (continued)

Trang 26

The output for this method is shown here:

topLevel.GetRoot().DepthFirstSearch("Four").Value( ).ToString( )); Console.WriteLine("topLevel.DepthFirstSearch(Five): " +

topLevel.GetRoot().DepthFirstSearch("Five").Value( ).ToString( )); Console.WriteLine("\r\n\r\nBreadth First Search:");

Console.WriteLine("topLevel.BreadthFirstSearch(One): " +

topLevel.GetRoot().BreadthFirstSearch("One").Value( ).ToString( )); Console.WriteLine("topLevel.BreadthFirstSearch(Two): " +

topLevel.GetRoot().BreadthFirstSearch("Two").Value( ).ToString( )); Console.WriteLine("topLevel.BreadthFirstSearch(Three): " +

topLevel.GetRoot().BreadthFirstSearch("Three").Value( ).ToString( )); Console.WriteLine("topLevel.BreadthFirstSearch(Four): " +

topLevel.GetRoot().BreadthFirstSearch("Four").Value( ).ToString( ));}

Example 11-12 Using the NTree<T>, NTreeNodeFactory<T>, and NTreeNode<U> classes

Trang 28

Breadth First Search:

An n-ary tree isone that hasno limitation on the number of children each parent

node may contain This is in contrast to the binary search tree in Recipe 11.4, in which each parent node may contain only two children nodes.

NTree<T>is a simple class that contains only a constructor and three public methods.

Through thisobject, you can create an n-ary tree, set the root node, and obtain the

root node in order to navigate and manipulate the tree AnNTree<T>object that can contain at most three children is created in the following manner:

NTree<string> topLevel = new NTree<string>(3);

An NTree<T> object that can contain at most int.MaxValue children, which allows greater flexibility, is created in the following manner:

NTree<string> topLevel = new NTree<string>( );

The real work isdone in theNTreeNodeFactory<T>object and theNTreeNode<U>object, which isnested in theNTreeNodeFactory<T>class TheNTreeNodeFactory<T>class is an object factory that facilitatesthe construction of allNTreeNode<U>objects When the factory object iscreated, theNTree<T>object is passed in to the constructor, as shown here:

NTreeNodeFactory<string> nodeFactory = new NTreeNodeFactory<string>

(topLevel);

Therefore, when the factory object iscreated, it knowsthe maximum number of dren that a parent node may have The factory object providesa public method,

chil-CreateNode, that allowsfor the creation of an NTreeNode<U> object If an

IComparable<T>type object is passed into this method, theIComparable<T>object will

be contained within thisnew node in thenodeValuefield If anullis passed in, the newNTreeNode<U>object will contain the objectUwith it initialized using the default keyword The String object can be passed in to this parameter with no modifica- tions Node creation is performed in the following manner:

NTreeNode<string> one = nodeFactory.CreateNode("One");

NTreeNode<string> two = nodeFactory.CreateNode("Two");

NTreeNode<string> three = nodeFactory.CreateNode("Three");

NTreeNode<string> four = nodeFactory.CreateNode("Four");

NTreeNode<string> five = nodeFactory.CreateNode("Five");

NTreeNode<string> six = nodeFactory.CreateNode("Six");

NTreeNode<string> seven = nodeFactory.CreateNode("Seven");

NTreeNode<string> eight = nodeFactory.CreateNode("Eight");

NTreeNode<string> nine = nodeFactory.CreateNode("Nine");

Trang 29

The NTreeNode<U> class is nested within the factory class; it is not supposed to be used directly to create a node object Instead, the factory will create a node object and return it to the caller.NTreeNode<U>hasone constructor that acceptstwo param- eters: value, which isan object of typeUused to store an object implementing the

IComparable<T>interface; and an integer value,maxChildren, which isused to define the total number of child nodesallowed It isthenodeValuefield that you use when you are searching the tree for a particular item.

Adding a root node to theTopLevel NTree<T>object isperformed using theAddRoot

method of theNTree<T> object:

topLevel.AddRoot(one);

Each NTreeNode<U> object containsa field called childNodes Thisfield isan array containing all child nodesattached to thisparent node object The maximum num- ber of children—obtained from the factory class—provides this number, which is used to create the fixed-size array This array is initialized in the constructor of the

NTreeNode<U> object.

The following code shows how to add nodes to this tree:

// Add nodes to root

to the end of the method.

If theRemoveNodemethod is successful, the array containing all child nodes of the rent node iscompacted to prevent fragmentation, which allowsnodesto be added later in a much simpler manner TheAddNodemethod only hasto add the child node

cur-to the end of this array as opposed cur-to searching the array for an open element The following code shows how to remove a node:

// Remove all nodes below node 'Two'

// Nodes 'Five' and 'Six' are removed

topLevel.GetRoot( ).BreadthFirstSearch("Two").RemoveNode(0);

Trang 30

// Remove node 'Three' from the root node.

• Union of the items contained by the two container objects

• Intersection of the items contained by the two container objects

• Difference of the items contained by the two container objects

Solution

Use the built inHashSet<T> object.

The methods defined in Table 11-8 are of particular interest to using a HashSet<T>

whereobj is the object of type T to add to thisHashSet

Remove method Removes an existing object from the currentHashSet<T> object Its syntax is:

Remove(T obj)

whereobj is the object of type T to remove from thisHashSet

RemoveWhere method Removes an existing object from the currentHashSet<T> object Its syntax is:

RemoveWhere(Predicate<T> match)

wherematch is the condition in which must be satisfied in order to remove an item

or items from thisHashSet

Trang 31

Contains method Returns a Boolean indicating whether the object passed in exists within this

HashSet<T>object If a true is returned, the object exists; otherwise, it does not Itssyntax is:

Contains(T obj)

whereobj is the object of typeT to be searched for

UnionWith method Performs a union operation on the currentHashSet<T> object and a second

HashSet<T> object The currentHashSet<T> object is modified to contain theunion of these twoHashSet<T> objects Its syntax is:

UnionWith(HashSet<T> set)

whereset is the secondHashSet<T> object

IntersectionWith method Performs an intersection operation on the currentHashSet<T>object and a second

HashSet<T> object The currentHashSet<T> object is modified to contain theintersection of these twoHashSet<T> objects Its syntax is:

IntersectionWith(HashSet<T> set)

whereset is the secondHashSet<T> object

ExceptWith method Removes all elements in the passed inHashSet<T> object from theHashSet<T>

object on which this method was called The currentHashSet<T>object is modified

to contain the result of this operation Its syntax is:

ExceptWith(HashSet<T> set)

whereset is the secondHashSet<T> object

SymmetricExceptWith method Performs a difference operation on the currentHashSet<T> object and a second

HashSet<T> object The currentHashSet<T> object is modified to contain thedifference of these twoHashSet<T> objects Its syntax is:

SymmetricExceptWith(HashSet<T> set)

whereset is the secondHashSet<T> object

SetEquals method Returns a Boolean indicating whether a secondHashSet<T> object is equal to the

currentHashSet<T> object Its syntax is:

SetEquals(HashSet<T> set)

whereset is the secondHashSet<T> object

IsSubsetOf method Returns a Boolean indicating whether the currentHashSet<T>object is a subset of

a secondHashSet<T> object Its syntax is:

IsSubsetOf(Set<T> set)

whereset is the secondHashSet<T> object

IsSupersetOf method Returns a Boolean indicating whether the currentHashSet<T> object is a superset

of a secondHashSet<T> object Its syntax is:

IsSupersetOf(HashSet<T> set)

whereset is the secondHashSet<T> object

IsProperSubsetOf method Returns a Boolean indicating whether the currentHashSet<T> object is a proper

subset of a secondHashSet<T> object Its syntax is:

IsProperSubsetOf(Set<T> set)

whereset is the secondHashSet<T> object

Table 11-8 Members of the HashSet<T> class (continued)

Trang 32

Sets are containersthat hold a group of homogeneousobject types

Variousmathe-matical operations can be performed on sets, including the following:

Union

(A ∪ B)

Combinesall elementsof setAand setBinto a resultingHashSet<T>object If an object exists in both sets, the resulting unionedHashSet<T>object containsonly one of those elements, not both.

Intersection

(A ∩ B)

Combinesall elementsof setAand setBthat are common to bothAandBinto a resultingHashSet<T>object If an object exists in one set and not the other, the element is not added to the intersectionedHashSet<T> object.

Difference

(A–B)

Combinesall elementsof setA, except for the elementsthat are also membersof setB, into a resultingHashSet<T>object If an object exists in both setsAandB, it isnot added to the final differencedHashSet<T>object The difference isequiva- lent to taking the union of both sets and the intersection of both sets and then removing all elements in the unioned set that exist in the intersectioned set.

Subset

(A ⊂ B)

Returnstrueif all elementsof setAare contained in a second setB; otherwise, it returnsfalse SetB may contain elements not found inA.

IsProperSupersetOf method Returns a Boolean indicating whether the currentHashSet<T> object is a proper

superset of a secondHashSet<T> object Its syntax is:

IsProperSupersetOf(HashSet<T> set)

whereset is the secondHashSet<T> object

Overlaps method Returns a Boolean indicating whether the currentHashSet<T> object overlaps a

secondHashSet<T> object Its syntax is:

Overlaps(HashSet<T> set)

whereset is the secondHashSet<T> object

Table 11-8 Members of the HashSet<T> class (continued)

Trang 33

The following code creates and populates twoHashSet<T> objects:

HashSet<int> set1 = new HashSet<int>( );

HashSet<int> set2 = new HashSet<int>( );

The union operation can be performed by using theUnionWithmethod and passing in

a HashSet<T>with which to union the current HashSet<T> Essentially, the resulting set contains elements that exist in either of the two HashSet<T> objectsor both

HashSet<T> objects The following code demonstrates the union operation:

set1.UnionWith(set2);

The intersection operation is set up similarly to the union operation To perform an intersection between twoHashSet<T>objects, use theIntersectWithmethod Essen- tially, an element must be in bothHashSet<T> AandHashSet<T> Bin order for it to be placed in the resultingHashSet<T>object The following code demonstrates the inter- section operation:

set1.IntersectionOf(set2);

The difference operation isperformed through the SymmetricExceptWith method Essentially, only elements in either set, but not both, are placed in the resulting set The following code demonstrates the difference operation:

set1.SymmetricExceptWith(set2);

Trang 34

The subset operation is performed only through a single method calledIsSubsetOf The superset operation is also performed using a single method calledIsSupersetOf The following code demonstrates this operation:

bool isSubset = set1.IsSubsetOf(set2);

bool isSuperset = set1.IsSupersetOf(set2);

The equivalence operation isperformed by using theSetEqualsmethod The ing code demonstrates this operation:

bool isEqual = set1.Equals(set2);

See Also

The “HashSet and LINQ Set Operations” topics in the MSDN documentation.

Trang 35

• Encoding methods for character data.

• Selecting the correct way (based on usage) to access files via streams.

The second set looks at directory- or folder-based programming tasks such as file ation as well as renaming, deleting, and determining attributes The third set deals with the parsing of paths and the use of temporary files and paths The fourth set deals with more advanced topics in filesystem I/O, such as:

cre-• Asynchronous reads and writes.

• Monitoring for certain file system actions.

• Version information in files.

• Using P/Invoke to perform file I/O.

The file-interactions section comes first since it sets the stage for many of the recipes

in the temporary file and advanced sections This is fundamental knowledge that will help you understand the other file I/O recipes and how to modify them for your pur- poses The various file and directory I/O techniques are used throughout the more advanced examplesto help show a couple of different waysto approach the prob- lems you will encounter working with file system I/O.

Unless otherwise specified, you need the followingusingstatements in any program that uses snippets or methods from this chapter:

Trang 36

To display a file’s timestamps, you can use either the static methods of theFileclass

or the instance properties of the FileInfo class The static methods are

GetCreationTime,GetLastAccessTime, andGetLastWriteTime Each hasa single eter, the path and name of the file for which timestamp information is to be returned, and returnsa DateTime value containing the relevant timestamp For example:

public static void DisplayFileTimestamps(string path)

The instance properties of theFileInfo class areCreationTime, LastAccessTime, and

LastWriteTime Each returnsaDateTimevalue containing the respective timestamp of the file represented by the FileInfo object The DisplayFileInfoTimestamps exten- sion method allows you to report those values directly from aFileInfo:

public static void DisplayFileInfoTimestamps(this FileInfo fileInfo)

To modify a file’s timestamps, you can use either the static methods of theFileclass

or the instance properties of the FileInfo class The static methods are

SetCreationTime,SetLastAccessTime, andSetLastWriteTime All of them take the path and name of the file for which the timestamp isto be modified asthe first parameter and aDateTimevalue containing the new timestamp as the second, and each returns

void To set them all at once, use theModifyFileTimestamps method:

public static void ModifyFileTimestamps(string path)

Trang 37

The instance properties are the same as the properties used to display timestamp information:CreationTime,LastAccessTime, orLastWriteTime To set the timestamp, assign a value of typeDateTimeto the relevant timestamp property To set all of these properties at once, use theModifyTimestamps extension method forFileInfo:

public static void ModifyTimestamps(this FileInfo fileInfo, DateTime dt)

FileInfo fileInfo = new FileInfo(path);

// Display whether this file is hidden

Console.WriteLine("Is file hidden? = " +

((fileInfo.Attributes & FileAttributes.Hidden) ==

In addition to timestamp information, a file’s attributes may also be obtained and modified This is accomplished through the use of the public instance Attributes

property found on a FileInfo object Thisproperty returnsor modifiesa

FileAttributes enumeration The FileAttributes enumeration ismade up of bit flags that can be turned on or off through the use of the bitwise operators&,|, or^ Table 12-1 lists each of the flags in theFileAttributes enumeration.

Trang 38

In many cases, more than one of these flags can be set at one time One case in which thisisnot the case isfor theNormalflag, which must be used alone (see description for more details).

Fileclass or the instance MoveTomethod of theFileInfoclass The staticFile.Move

method can be used to rename a file in the following manner:

Table 12-1 FileAttributes enumeration values

Member name Description

Archive Represents the file’s archive status that marks the file for backup or removal

Compressed Indicates that the file is compressed

Device This option is reserved for future use

Directory Indicates that this is a directory

Encrypted Indicates that a file or directory is encrypted In the case of a file, its contents are encrypted In

the case of a directory, newly created files will be encrypted by default

Hidden Indicates a hidden file

Normal Indicates that the file has no other attributes; as such, this attribute cannot be used in

combina-tion with others

NotContentIndexed Indicates that the file is excluded from the content index service

Offline Indicates that the state of the file is offline and its contents will be unavailable

ReadOnly Indicates that the file is read-only

ReparsePoint Indicates a reparse point, a block of data associated with a directory or file.

SparseFile Indicates a sparse file, which may take up less space on the filesystem than its reported size

because zeros in the file are not actually allocated on disk

System Indicates that the file is a system file

Temporary Indicates a temporary file It may reside entirely in memory

Trang 39

public static void RenameFile(string originalName, string newName)

{

File.Move(originalName, newName);

}

This code has the effect of renaming theoriginalName file tonewName.

TheFileInfo.MoveToinstance method can also be used to rename a file, and this can

be exposed directly from the FileInfo instance using an extension method The

Rename extension method gives easy access to rename functionality right from the

Trang 40

The NET Framework providestheEnvironment.NewLineconstant, which represents

a newline on the given platform This is the newline string used by all of the work providedWriteLine methods internally (includingConsole,Debug, andTrace) There are a few different scenarios in which this could be useful:

frame-• Formatting a block of text with newlines embedded within it:

// Remember to use Environment.NewLine on every block of text

// we format that we want platform-correct newlines at the end of

string line;

line = String.Format("FirstLine {0} SecondLine {0} ThirdLine {0}",

Environment.NewLine);

// Get a temp file to work with

string file = Path.GetTempFileName( );

using (FileStream stream = File.Create(file))

• You need to use a different newline character than the default one used by

StreamWriter(which happensto beEnvironment.NewLine) You can set the line that a StreamWriterwill use once so that all WriteLinesperformed by the

new-StreamWriter use that newline instead of having to manually do it each time: // Set up a text writer and tell it to use a certain newline

// string

// Get a new temp file

file = Path.GetTempFileName( );

line = "Double spaced line";

using (StreamWriter streamWriter = new StreamWriter(file))

{

// Make this always write out double lines

streamWriter.NewLine = Environment.NewLine + Environment.NewLine;

// WriteLine on this stream will automatically use the newly specified // newline sequence (double newline, in our case)

• NormalWriteLine calls:

// Just use any of the normal WriteLine methods, as they use the

// Environment.NewLine by default

Ngày đăng: 12/08/2014, 09:22