线性表的一种常见存在形式,链表。在链式存储的过程中,每个元素Node不仅包含元素本身的信息,还包含元素之间的逻辑信息。前驱结点包含后继结点的地址信息(指针域),可以很方便的找到后继结点的位置。
今天先来认识一下单链表:每个结点除包含数据域外,只设置一个指针域,来指向后继结点,这样构成的链表就是单链表。
在链表中都会有一个头指针,便于插入和删除,可以通过头结点,沿着链,遍历每一个链表中的结点。
单向链表中结点的结构:
单链表结构:
终端指针域为空,表示链表的结束。
简单实现一下单链表:
定义链表单个结点类:
class Node
{
public Node(object value)
{
item = value;
}
//数据
public object item;
//指针(指向后继结点)
public Node next;
}
单链表类:
class SingleLinkList
{
//元素个数
private int count;
public int Count
{
get
{
return count;
}
}
//头结点
private Node headNode;
}
通过索引获取指定元素
//查找指定索引下的元素
public Node GetByIndex(int index)
{
if (index < 0 || index >= count)
{
throw new ArgumentOutOfRangeException("index", "Out Of Range");
}
Node temp = headNode;
//通过头结点 往下找
for (int i = 0; i < index; i++)
{
temp = temp.next;
}
return temp;
}
添加元素
//在链表尾部插入元素
public void AddToLast(object value)
{
// 在链表结尾处添加
Node newNode = new Node(value);
if (headNode == null)
{
//链表为空,直接作为头结点
headNode = newNode;
}
else
{
//插入链尾
GetByIndex(count - 1).next = newNode;
}
count++;
}
//在指定索引处插入元素
public void AddToIndex(int index ,object value)
{
Node tempNode;
if (index==0)
{
if (headNode==null)
{
headNode = new Node(value);
}
else
{
tempNode = new Node(value);
//修改指针
tempNode.next = headNode;
headNode = tempNode;
}
}
else
{
//插入点前后结点
Node preNode = GetByIndex(index - 1);
Node nextNode = preNode.next;
tempNode = new Node(value);
preNode.next = tempNode;
tempNode.next = nextNode;
}
count++;
}
移除指定索引位置元素,输出链表元素
//移除指定索引的元素
public void RemoveAt(int index)
{
if (index==0)
{
headNode = headNode.next;
}
else
{
Node preNode = GetByIndex(index - 1);
if (preNode.next==null)
{
throw new ArgumentOutOfRangeException("index", "Out Of Range");
}
else
{
//同样修改指针所指
preNode.next = preNode.next.next;
}
}
count--;
}
//输出链表的元素
public string ConsoleContent()
{
string str = "";
for (Node temp = headNode; temp != null; temp = temp.next)
{
str += temp.item.ToString() + " ";
}
return str;
}
}
被删除的结点并没有立即在内存中被真正删除,还在原来位置,直到GC运行时才会被真正删除。
测试如下:
SingleLinkList TempList = new SingleLinkList();
Console.WriteLine("元素个数:"+TempList.Count);
TempList.AddToLast(2);
TempList.AddToLast(3);
Console.WriteLine(TempList.ConsoleContent());
TempList.AddToIndex(1,4);
TempList.AddToIndex(2, 5);
Console.WriteLine(TempList.ConsoleContent());
TempList.RemoveAt(3);
Console.WriteLine(TempList.ConsoleContent());
Console.WriteLine("元素个数:"+TempList.Count);
Console.ReadKey();
总的来说单链表的操作很简单, 与顺序表比较来说,不需要移动元素,但是元素的定位,会导致效率下降,特别在元素很多的时候。微软给出的建议使用在十个或者10个一下元素。
我们可以尝试给单链表添加尾指针,来迅速地定位到尾节点,当我们遇到只添加数据,而很少删除数据的时候,那么这种链表就会非常合适,之后会修改这个单链表的代码,给它添加一个tail尾指针来解决这种效率问题~~~