循环、双向链表
前面介绍的是单链表,是严格从头到尾的链表,具有易于增删改查的优点。它的首结点被头指针所指向,尾结点指向虚空(NULL)。
为了表现更丰富的数据,链表也有变种,那就是循环链表和双向链表。
循环链表
循环链表是首结点和尾结点建立了逻辑关系的链表,就像项链一样,练成了一个闭环。假设现在手上有一个现成的单链表,那么要怎么把它改成循环链表呢?
很简单,让尾结点指向首结点即可。并且依然保留了表达整个链表的头指针,头指针也指向首结点。当然,对于循环链表,也可以用尾指针(rear)来表达,尾指针指向尾结点的指针域,实际上依然是最终指向首节点。
循环链表的存在更多是方便了链表的合并,这个操作就要用到尾指针这个工具了。
p = rearA->next; //p存储了链表A的头结点地址
rearA->next = rearB->next->next; //将A的头结点变成b的首结点(不是头结点)
q = rearB->next; //q存储链表B的头结点
rearB->next = p; //链表B的尾指针指向A的头结点
free(q);//舍弃掉B的头结点
这里也更加清晰地解释了头结点的作用,头结点一般不存储真正的数据,在链表合并过程中,接在后面的链表的头结点会被前面的链表的尾结点所取代。
双向链表
双向链表是每个节点与相邻的节点都有逻辑关系的链表。
双向链表的结点结构:
typedef struct DulNode{
int data;
struct DulNode *prior; //直接前驱指针
struct DulNode *next; //直接后继指针
}
prior指向这个节点前面的结点,next指向后面的结点。
因为多了一层逻辑关系,双向链表在操作上虽然与单链表类似,但复杂度更高。而双向链表的作用一般是提供良好的对称性,使一些特定算法更高效。