循环链表(单、双循环)

 

图示为双链表结构 

 观察循环链表的结构,不难发现单循环链表仅仅在单向链表的基础上,把最后一个节点的Next指针指向链表头节点。而双循环链表仅在双向链表的基础上,同样把最后一个节点和链表头节点建立联系。

由此:在了解单向链表和双向链表后,单向循环和双向循环就比较简单了。


循环链表结构实现:

typedef int DataType;	// 数据类型
// 循环链表节点    形同  普通链表节点
// 单向循环链表节点  --->  单链表节点
// 双向循环链表节点  --->  双链表节点
class CNode { 
public:
	// 此处 this指针 赋值给 Pre 和 Next 让它们指向该节点本身
	CNode(DataType data) :Data(data), Pre(this), Next(this) {}
	DataType Data;		// 数据域
	CNode* Pre;			// 前驱指针
	CNode* Next;		// 后继指针
};
// 循环链表
class CList {
public:
	CNode* Head = NULL;
};

常规操作实现


 :

// 头插 (会改变链表头)
void headPush(CList &CL, DataType data) { 
	if (CL.Head == NULL) {
		CL.Head = new CNode(data);
		return;
	}
	CNode* T = new CNode(data);

//  !-- 先修改 后继 再修改 前驱 ,顺序不能乱 --!
	// 修改后继指针
	T->Next = CL.Head; 
	CL.Head->Pre->Next = T;
	// 修改前驱指针
	T->Pre = CL.Head->Pre;
	CL.Head->Pre = T;
	CL.Head = T;
}
// 尾插 (不会改变链表头) // 跟头插无明显区别 ,仅不更改 链表头
void endPush(CList &CL, DataType data) {
	if (CL.Head == NULL) {
		CL.Head = new CNode(data);
		return;
	}
	CNode* T = new CNode(data);
	// 先改后继,再改前驱
	// 修改后继
	T->Next = CL.Head;
	CL.Head->Pre->Next = T;
	// 修改前驱
	T->Pre = CL.Head->Pre;
	CL.Head->Pre = T;
}

 :

// 头删
void headPop(CList &CL) { 
	if (CL.Head == NULL) {
		return;
	}
	CNode* T = CL.Head->Next;
	if (T == CL.Head) {		//  仅一个节点
		CL.Head = NULL;
	}
	else {
		T->Pre = CL.Head->Pre;
		CL.Head->Pre->Next = T;
		CL.Head = T;		// 更新链表头
	}
}
// 尾删
void endPop(CList &CL) {
	if (CL.Head == NULL) {
		return;
	}
	CNode* T = CL.Head->Pre;
	// 同头插方法相同,不过无需更改链表头
	if (T == CL.Head) {		// 仅一个节点
		CL.Head = NULL;
	}
	else {
		CL.Head->Pre = T->Pre;
		T->Pre->Next = CL.Head;
		// 无需更改链表头
	}
}
// 删除指定节点
bool DelCNode(CList &CL, DataType data) {
	if (CL.Head == NULL) {
		return false;
	}
	CNode* T = CL.Head;
	int flat = false;		// 是否存在data节点的标志
	do {
		if (T->Data != data) {
			T = T->Next;
		}
		else {
			flat = true;	// 更改标志为真
			break;
		}
	} while (T != CL.Head);
	// 没找到data节点
	if (flat != true) {		
		return false;
	}
	CNode* N = T->Next;
	if (N == T) {				// 仅剩一个节点
		CL.Head = NULL;
	}
	else {
		N->Pre = T->Pre;
		T->Pre->Next = N;
		if (T == CL.Head) {		// 如果待删节点在链表头,更改 N 为新链表头
			CL.Head = N;
		}
	}
	return true;
}

 :

// 查找某节点是否存在
bool FindCNode(CList &CL, DataType data) {
	if (CL.Head == NULL) {
		return false;
	}
	CNode* T = CL.Head;
	do {
		if (T->Data == data) {
			return true;
		}
		T = T->Next;
	} while (T != CL.Head);
	return false;
}

 :

// 改 (data1-->data2)
bool ChangeNode(CList &CL, DataType data1, DataType data2) { 
	if (CL.Head == NULL) {
		return false;
	}
	CNode* T = CL.Head;
	do {
		if (T->Data == data1) {
			T->Data = data2;
			return true;
		}
		T = T->Next;
	} while (T != CL.Head);
	return false;
}

遍历: 

// 顺序遍历
void Traverse(CList &CL) {
	if (CL.Head == NULL) {
		return;
	}
	CNode* T = CL.Head;
	// 巧用 do-while 循环 再一次回到链表头停止
	do {
		cout << T->Data << " ";
		T = T->Next;
	} while (T!=CL.Head);
	cout << endl;
}
// 逆序遍历
void ReTravese(CList &CL) {
	if (CL.Head == NULL) {
		return;
	}
	CNode* T = CL.Head->Pre;
	do {
		cout << T->Data << " ";
		T = T->Pre;
	} while (T != CL.Head->Pre);
	cout << endl;
}

获取链表长度: 


小结:此处仅实现双向循环链表,而单向循环链表比双向循环链表更容易,不再赘述,实现基本思想大同小异。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值