循环链表核心思想和单向链表其实一样,数据结构没变,就是她的尾节点又指向了头结点,饶了个圈,循环了一下。
和双向链表不一样,循环其实就尾节点算有程序上的前驱后继而已。
尾指针循环链表就是在原基础上又添加了尾指针指向尾节点,在合并的时候方便,知道了尾指针能得到尾节点和头结点。
我只写了和单向链表不一样的部分,注释也只是注释了和单向链表不一样的地方。所以显得(反正单向里面都有了)
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef int datatype;
typedef struct Node {
datatype data;
struct Node *pNext;
}Node, *pNode;
//=============================
//头指针循环链表
void Init(pNode &pHead);//初始化
void CreateTail(pNode pHead);//尾插法建表
bool isEmpty(pNode pHead);//判断是否为空
int length(pNode pHead);//求链表长度
void Traverse(pNode pHead);//遍历
//=================================
//尾指针循环链表
void CreateTail1(pNode pHead,pNode &tailpointer);
//void Merge1(pNode &Ahead,pNode &Bhead,pNode tailpointerA,pNode tailpointerB);//合并俩链表
//==============================
void Init(pNode &pHead) {
pHead = (pNode)malloc(sizeof(Node));
if(!pHead ) {
printf("failed!\n");
exit(-1);
}
pHead->pNext = pHead; //这里和单向链表不一样,形成一个圈
}
//===============================================
void CreateTail(pNode pHead) {
printf("输入节点个数:");
int n,i = 0;
scanf("%d",&n);
pNode pTail = pHead ;
while( i < n) {
datatype item;
printf("请输入节点值:");
scanf("%d",&item);
pNode pNew = (pNode)malloc(sizeof(Node));
pNew->data = item;
//这里和单向链表不一样
pTail->pNext = pNew;//把pNew给尾节点做后继
pNew->pNext = pHead;//pNew指向了头
pTail = pNew;//让pNew做尾节点
i++;
}
return ;
}
//=====================================
//判断是否为空
bool isEmpty(pNode pHead) {
if(pHead == pHead->pNext ) { //这里和单向链表不一样,因为循环嘛
printf("空!\n");
return true;
}else
return false;
}
//=====================================
//求链表长度
int length(pNode pHead) {
pNode p = pHead->pNext;
int count = 0;
if(isEmpty(pHead ))
return count;
while(p != pHead ) { //这里和单向链表不一样
count++;
p = p->pNext ;
}
return count;
}
//=====================================
//遍历
void Traverse(pNode pHead) {
if(isEmpty(pHead)) {
return ;//空表就没啥遍历可言了
}
pNode p = pHead->pNext;
while(p != pHead) {//绕个圈 已经没有空节点了
printf("%d ",p->data );//改数据类型记得的时候%d也要改
p = p->pNext ;
}
printf("\n");
return;
}
/************************************************************************/
/* 分割线 */
/************************************************************************/
void CreateTail1(pNode pHead,pNode &tailpointer) {
// tailpointer//尾指针 指向尾节点和头指针指向首节点一个意思
printf("输入节点个数:");
int n,i = 0;
scanf("%d",&n);
pNode pTail = pHead ; //尾节点
while( i < n) {
datatype item;
printf("请输入节点值:");
scanf("%d",&item);
pNode pNew = (pNode)malloc(sizeof(Node));
pNew->data = item;
//这里和单向链表不一样
pTail->pNext = pNew;//把pNew给尾节点做后继
pNew->pNext = pHead;//pNew指向了头
pTail = pNew;//让pNew做尾节点
tailpointer->pNext = pTail;//尾指针始终指向尾节点
i++;
}
return ;
}
//==============================
/*
这里合并只是为了演示下尾指针法合并的方便性,
所以只是单纯的把俩个链表连接起来而已
分析一下,表都有头结点 尾指针,那么我a的尾节点(不是尾指针哈)连上b的首节点(不是头结点哈),
然后b的尾节点再指向a的头指针,合并完毕,等会去画个图。
Ahead-1-2-3-tailpointerA Bhead-6-7-tailpointerB
^|_________| ^|_______|
不够形象,大致酱紫吧。
|-----------------------|
Ahead-1-2-3-tailpointerA Bhead-6-7-tailpointerB
^|___________________________________|
*/
pNode Merge1(pNode tailpointerA,pNode tailpointerB) {
pNode Atailnode = tailpointerA->pNext;// a的尾节点3
pNode Ahead = Atailnode->pNext;//a的头结点
pNode Btailnode = tailpointerB->pNext;// b的尾节点7
pNode Bhead = Btailnode->pNext;//B的头结点
Atailnode->pNext = Bhead->pNext;//a的尾节点3指向b的首节点6
Btailnode->pNext = Ahead;//b的尾节点指向a的头结点
tailpointerA->pNext = Btailnode;//a的尾指针指向b的尾节点7
return Ahead;//返回a的头结点
}
//===========================================
int main() {
pNode p1;
// Init(p1);
// CreateTail(p1);
// printf("长度是:%d\n ",length(p1));
// Traverse(p1);
Init(p1);
pNode tailpointer1 =(pNode)malloc(sizeof(Node ));//不能这样tailpointer = p;因为p是个双向链表,不信你试试
tailpointer1->pNext = NULL;//算是吧tailpointer1给初始化的完整了,挺烦的 艹
CreateTail1(p1,tailpointer1);
printf("长度是:%d\n ",length(p1));
Traverse(p1);
pNode p2;
Init(p2);
pNode tailpointer2 = (pNode)malloc(sizeof(Node ));
tailpointer2->pNext = NULL;
CreateTail1(p2,tailpointer2);
printf("长度是:%d\n ",length(p2));
Traverse(p2);
printf("\n合并:\n");
if(tailpointer1->pNext && tailpointer2->pNext) {//空表没意思
p1 = Merge1(tailpointer1,tailpointer2);
Traverse(p1);
}
free(p1);
free(p2);
return 0;
}