【数据结构】Doubly-Linked List双向链表(更新时间:2016-04-03)
啊哈,Doge 来补之前遗留下的关于链表的扩展的东西了
在学习了之前的单链表的基础上,Doge在这里再给大家介绍一下链表的一些拓展,主要是关于链表的指针域不同的连接方式会形成不同的链表类型。
Doubly-Linked List
双向链表在单向链表的基础上,增加一个反向指针来使得在访问的过程中能够不再受限制于单向访问。
下面给出示意图:
代码示例:
由于双向链表中从一个节点都可以访问到另外一个节点,因此单链表中的表头节点在这里就没有任何意义。Doge 通过插入函数来直接初始化双向链表而不再单独设置初始化函数,因为单独设置初始化函数的时候没有数值就无法构造出有意义的链表。同时,双向链表中非常经典的操作函数就是Remove函数,基础的remove就是将节点两端互相连接,在这里 Doge 稍微扩展之后将删除节点的功能也加入到了Remove中。
struct ListNode; //定义链表节点结构
typedef struct ListNode *PtrToNode; //定义结点指针类型
typedef PtrToNode LinkedList; //定义链表头节点类型
typedef PtrToNode LLNode; //定义节点类型
typedef int ElementType; //定义数据类型
struct ListNode //节点结构
{
ElementType Element; //数值域
LLNode Left, Right; //指针域
//也有人会使用 Pre 和 Next 作为指针的名字,纯看个人喜欢了
};
//辅助函数
int IsLast( LLNode T ) //判断链表是否为最后一个节点
{
return ( T == T->Right );
}
//插入函数
LinkedList Insert( LinkedList L, ElementType X ) //插入(初始节点右侧)
{
LLNode P;
P = ( LLNode ) malloc ( sizeof( ListNode ) ); //分配插入节点的空间
P->Element = X; //节点数值域赋值
if( L == NULL ) //链表中误解点
{
L = P; //设置第一个节点
L->Left = L->Right = L; //初始化循环链接
}
else
{
P->Right = L->Right; //链接入右侧链表
L->Right = P; //节点插入右侧
P->Right->Left = P; //链接入左侧链表
P->Left = L; //节点插入初始节点右侧
}
return L;
}
//查找函数
LLNode Find( LinkedList L, ElementType X ) //查找元素返回节点
{
LLNode P = L; //游标初始化
if( P->Element == X ) //判断头节点是否是要查找的节点
return P;
L = L->Right;
while( P->Right != L && P->Element != X ) //遍历查找指定元素
P = P->Right;
if( P == L ) //未找到元素,返回NULL
return NULL;
else //找到则返回节点
return P;
}
//移除函数
LinkedList Remove( LinkedList L, LLNode T ) //将节点移出链表
{
if( IsLast( L ) ) //如果只剩一个节点
free( L );
else if( T == L ) //移除第一个节点
{
L = L->Right;
Remove( L, T );
}
else //移除其他节点
{
T->Left->Right = T->Right;
T->Right->Left = T->Left;
free(T);
return L;
}
}
//删除节点函数
LinkedList Delete( LinkedList L, ElementType X ) //删除
{
LLNode P = Find( L, X ); //使用查找函数
if( P == NULL ) //返回值为NULL
cout << X << " is not found in the LinkedList!\n";
else //删除节点并释放存储空间
Remove( L, P );
return L;
}
//清空函数
LinkedList MakeEmpty( LinkedList L ) //清空并删除链表
{
LLNode tmp = L->Right; //游标指向实际存储表的头
while( tmp != L ) //遍历清空链表
{
Remove( L, tmp );
tmp = L->Right;
}
free( L ); //删除最后一个节点
return L;
}