然而,由于我是C#的新手,我被上述讨论初始部分列出的语法所困惑了。一个名为Node的类被声明,并且在类内又有一个被声明为“public Node next”的语句。这个语句是构造函数吗?请帮忙解答。
public class Node {
public Node next;
public Object data;
}
public class Node {
public Node next;
public Object data;
}
Node
类型包含对列表中下一项的引用,这就是您发布的 Node
类型中的 next
字段所表示的内容。该引用用于允许迭代列表。LinkedList
类(或您想要称呼它的任何名称)将包含对列表中第一项的单个 Node
引用。从第一个节点开始,您可以通过获取 next
字段来遍历整个列表。当 next
为 null 时,您已经到达了列表的末尾。public class LinkedList
{
public class Node
{
// link to next Node in list
public Node next = null;
// value of this Node
public object data;
}
private Node root = null;
public Node First { get { return root; } }
public Node Last
{
get
{
Node curr = root;
if (curr == null)
return null;
while (curr.next != null)
curr = curr.next;
return curr;
}
}
}
First
属性只是返回根节点,也就是列表中的第一个节点。而 Last
属性则从根节点开始遍历整个列表,直到找到一个其 next
属性为 null 的节点,表示已经到达了列表的末尾。
这使得向列表中添加元素变得非常简单:
public void Append(object value)
{
Node n = new Node { data = value };
if (root == null)
root = n;
else
Last.next = n;
}
要删除一个节点,你需要找到它在列表中的前一个节点,然后更新该节点的next
链接,使其指向要删除的节点的下一个节点:
public void Delete(Node n)
{
if (root == node)
{
root = n.next;
n.next = null;
}
else
{
Node curr = root;
while (curr.next != null)
{
if (curr.next == n)
{
curr.next = n.next;
n.next = null;
break;
}
curr = curr.next;
}
}
}
除了在列表中插入值,交换节点等操作之外,您还可以执行一些其他操作。在节点后插入速度很快,而在节点前插入速度较慢,因为您需要定位到前一个节点。如果您真的希望实现快速的“插入前”操作,则需要使用双向链表,其中Node
类型具有next
和previous
链接。
针对您在评论中提出的问题,我想进一步解释一下...
C# 中的所有类型都可以分为两类:值类型和引用类型。这些名称反映了它们在代码块之间传递的方式:值类型是按值传递的(将值复制到新变量中),而引用类型是按引用传递的(将引用/指针复制到新变量中)。区别在于,对值类型参数的更改不会影响调用者对该值的副本,而对引用类型参数的更改将反映在调用者对该引用的副本中。
对变量赋值时也是如此。在下面的示例中,当更改 b
时,a
的值不会改变:
int a = 0;
int b = a;
b = 1;
这相当直观。可能会让你困惑的是,在C#中,struct
也是值类型:
public struct test
{
public string value;
}
static void Main()
{
test a;
a.value = "a";
test b = a;
b.value = "b";
Console.WriteLine("{0} {1}", a.value, b.value);
}
a b
,因为当你将 a
赋值给 b
时,会创建一个副本。但是如果我们将结构体改为类:public class test
{
public string value;
}
static void Main()
{
test a = new test(); // Note the 'new' keyword to create a reference type instance
a.value = "a";
test b = a;
b.value = "b";
Console.WriteLine("{0} {1}", a.value, b.value);
}
因为变量b
是对与变量a
引用相同的对象的引用,所以这里的输出将是b b
。这两个变量引用同一个对象。
如果您来自C/C++或其他类似的语言,您可以将引用类型变量视为指针。虽然不完全相同,但C#确实有指针(它们被隐藏在正常托管代码中),但它足够接近。在将其指向类型的实例之前,它并不完全可用。就像在C/C++中的char*
在指向某个地方之前并不特别有用。
Joseph Albahari(撰写了一篇关于值类型和引用类型的优秀文章:C#概念:值类型与引用类型。这非常值得一读,他写的大部分内容都很好。我还强烈建议您考虑购买他的C# in a Nutshell书籍之一。
创建单向链表很简单。让我们尝试理解其概念。如果概念清晰,那么你就能理解逻辑本身。单向链表具有两个部分的节点。一个部分包含数据值,另一个部分包含下一个节点的引用地址。看一下以下代码:
首先,我们需要创建链表节点类。
/// <summary>
/// Creating the Real World Entity of Linked List Node
/// </summary>
public class LinkedListNode
{
public Object Value { get; set; }
public LinkedListNode Next { get; set; }
}
这里的类有“Value”和“Holder”,用于持有序列中下一个节点的引用。接下来,我们需要创建链表本身。
/// <summary>
/// Creating the Linked List Class Itself. It defines the First and Last Nodes of Linked List
/// </summary>
public class LinkedList
{
public LinkedListNode First { get; set; }
public LinkedListNode Last { get; set; }
/// <summary>
/// Method to Add items into the Linked List
/// </summary>
/// <param name="_value"></param>
public void AddToLinkedList(object _value)
{
LinkedListNode node = new LinkedListNode();
node.Value = _value;
if (First == null)
{
First = node;
Last = node;
}
else
{
Last.Next = node;
Last = node;
}
}
/// <summary>
/// Method to display all items. We can further implement the IEnumerable interface
/// to Yield IEnumerator Interface.
/// </summary>
public void DisplayAllItems()
{
LinkedListNode current = First;
while (current != null)
{
Console.WriteLine(current.Value);
current = current.Next;
}
}
}
在这里,关键是向链表中添加项目。首先,我们需要检查链表是否存在。我们检查链表中的第一个或头结点。如果它为空,我们将节点分配为第一个入口点。此时,最后一项就是第一项本身。
现在,我们来看看如何添加和显示项目
class Program
{
static void Main(string[] args)
{
LinkedList singlyLinkedList = new LinkedList();
singlyLinkedList.AddToLinkedList(4);
singlyLinkedList.AddToLinkedList(5);
singlyLinkedList.AddToLinkedList(7);
singlyLinkedList.AddToLinkedList(2);
singlyLinkedList.AddToLinkedList(1);
singlyLinkedList.AddToLinkedList(10);
singlyLinkedList.DisplayAllItems();
Console.ReadLine();
}
}
如果有任何问题,请告诉我 :)
请记住,链表不仅保存数据,还保存指向列表中下一个节点的引用/指针。由于在C#中类是引用类型,因此您不会看到在C或C++中可能看到的任何特殊语法。
struct Node
{
int Number;
struct Node* next; /* this points to the next node in the linked list */
};
new
关键字。 - Corey