带头结点的循环链表实现(C++)

带头结点的循环链表实现

先上代码,循环链表的数据结构定义和单链表是相同的。

#include <iostream>
#include <string>
using namespace std;

typedef struct{
	int num;
	string name;
}ElemType;

typedef struct Node{
	ElemType data;
	Node* next;
}Node,*CLList;

struct CircleLinkList{
	CLList CLL;
	int length;
};

下面对上述的数据结构定义进行解释:

  • ElemType是根据你所需要的数据类型去进行定义,此处主要是存储学生的学号和姓名信息。你也可以加上char sex,int score等等。
  • Node和 ∗ * CLList是对结点进行定义,一个节点包括数据和它指向的下一个节点。Node是一个结点本身,而 ∗ * CLList则是指向结点的指针。如果在此处定义了 ∗ * Node,那么它和 ∗ * CLList的作用是一样的。千万不要因为加了一个 ∗ * 就把两个弄混淆。
  • CircleLinkList顾名思义就是对循环链表进行定义,包括指向链表的指针和链表的长度。如果前面没有 ∗ * CLList,你也可以定义为Node ∗ * CLL,定义*CLList我个人觉得是为了看起来更直观,一看就知道是链表,而不是结点。

接下来的代码是循环链表的一些功能实现。

  • CL:表示循环链表整体(包括链表及其长度)
  • CL.CLL:表示循环链表本身(仅包括链表)
  • CL.length:表示循环链表长度(仅包括长度)
  • CL.CLL->next:表示循环链表中某结点下一个结点,这种形式在下面代码中表示头结点的下一个结点。
  • CL.CLL->data.num:表示循环链表中某结点的数据中的学号,这种形式在下面代码中表示头结点的数据中的学号。但我们一般不给头结点的数据赋值。
  • CL.CLL->data.name:表示循环链表中某结点的数据中的姓名,这种形式在下面代码中表示头结点的数据中的姓名。但我们一般不给头结点的数据赋值。
void InitCircleLinkList(CircleLinkList &CL){		//初始化
	CL.CLL = new Node();
	CL.CLL->next = CL.CLL;
	CL.length = 0;
}

int CircleLinkList_Length(CircleLinkList CL){		//获取链表长度
	return CL.length;
}

int CreateCircleLinkList_head(CircleLinkList &CL,int n){		//头插法创建循环链表
	if(n > 0){
		cout << "请输入学生的学号和姓名:" << endl;
		for(int i = 0;i < n;i++){
			Node* p = new Node();
			cin >> p->data.num >> p->data.name;
			p->next = CL.CLL->next;
			CL.CLL->next = p;
			CL.length++;
		}
		return 1;
	}
	return 0;
}

int CreateCircleLinkList_tail(CircleLinkList &CL,int n){		//尾插法创建循环链表
	if(n > 0){
		cout << "请输入学生的学号和姓名:" << endl;
		Node* temp = CL.CLL;
		for(int i = 0;i < n;i++){
			Node* p = new Node();
			cin >> p->data.num >> p->data.name;
			p->next = CL.CLL;
			temp->next = p;
			temp = p;
			CL.length++;
		}
		return 1;
	}
	return 0;
}

void Insert_CircleLinkList(CircleLinkList &CL,int i){		在i位置插入数据项
	if(i > 0 && i <= CL.length+1){
		Node* p = CL.CLL->next;
		if(i == 1){
			Node* q = new Node();
			cout << "请输入学生的学号和姓名:" << endl;
			cin >> q->data.num >> q->data.name;
			q->next = CL.CLL->next;
			CL.CLL->next = q;
			CL.length++;
			cout << "信息插入成功!" << endl;
		}
		else{
			int j = 1;
			while(j < i-1){
				p = p->next;
				j++;
			}
			Node* q = new Node();
			cout << "请输入学生的学号和姓名:" << endl;
			cin >> q->data.num >> q->data.name;
			q->next = p->next;
			p->next = q;
			CL.length++;
			cout << "信息插入成功!" << endl;
		}
	}
	else
		cout << "信息插入失败!" << endl;
}

void Delete_CircleLinkList(CircleLinkList &CL,int i){		//在i位置删除数据项
	if(i > 0 && i <= CL.length){
		if(i == 1){
			Node *q = CL.CLL->next;
			CL.CLL->next = q->next;
			delete q;
			CL.length--;
			cout << "信息删除成功!" << endl;
		}
		else{
			Node* p = CL.CLL->next;
			int j = 1;
			while(j < i-1){
				p = p->next;
				j++;
			}
			Node* q = p->next;
			p->next = q->next;
			delete q;
			CL.length--;
			cout << "信息删除成功!" << endl;
		}
	}
	else
		cout << "信息删除失败!" << endl;
}

void Print_CircleLinkList(CircleLinkList CL){		//遍历循环链表
	Node* p = CL.CLL->next;
	int i = 1;
	while(p!=CL.CLL){
		cout << "第" << i << "名学生信息如下:" << endl;
		cout << "学号为:" << p->data.num << endl;
		cout << "姓名为:" << p->data.name << endl;
		p = p->next;
		i++;
	}
}

void Clear_CircleLinkList(CircleLinkList &CL){		//清空链表
	CL.CLL->next = CL.CLL;
	CL.length = 0;
	cout << "链表已清空!" << endl;
}

int main(){
	CircleLinkList CL;
	InitCircleLinkList(CL);
	if(CreateCircleLinkList_head(CL,2)){
		cout << "链表(头插法)创建成功!" << endl;
	}
	Print_CircleLinkList(CL);
	cout << "链表长度为:" << CircleLinkList_Length(CL) << endl;
	Clear_CircleLinkList(CL);
	cout << "链表长度为:" << CircleLinkList_Length(CL) << endl;
	cout << "-----------------------------------------------------------------" << endl;
	if(CreateCircleLinkList_tail(CL,2)){
		cout << "链表(尾插法)创建成功!" << endl;
	}
	Print_CircleLinkList(CL);
	cout << "链表长度为:" << CircleLinkList_Length(CL) << endl;
	cout << "-----------------------------------------------------------------" << endl;
	Insert_CircleLinkList(CL,3);
	Print_CircleLinkList(CL);
	cout << "链表长度为:" << CircleLinkList_Length(CL) << endl;
	cout << "-----------------------------------------------------------------" << endl;
	Delete_CircleLinkList(CL,3);
	Print_CircleLinkList(CL);
	cout << "链表长度为:" << CircleLinkList_Length(CL) << endl;
	system("pause");
	return 0;
}

为了保证代码的完整性,我就先放代码再给大家进行解释了。刚开始写,很多格式上,逻辑上都有问题,欢迎小伙伴们指正~一起进步噢。大家可以根据代码去看下面的图,希望能够帮助大家更好的理解。

循环链表的变化主要是尾结点的next不是NULL,而是指向头结点。初始化的定义可根据下图来理解。

初始化链表

头插法图解。此处分为3个步骤。

  • 首先是创建要插入的结点;

  • 然后将新节点的next指向头结点CL的next,注-意时CL->next,而不是CL噢;

  • 最后再将CL->next指向新的节点;
    头插法1
    在这里插入图片描述在这里插入图片描述
    尾插法图解:针对尾插法,需要增加一个指针temp使其每次都指向链表的最后一个结点。解决方法就是每次增加一个结点,都让其指向它。分为四个步骤:

  • 首先是创建新节点,同时创建一个指针temp,让其指向头结点CL;

  • 然后将新节点的next域指向temp的next域;

  • 接下来将temp的next域指向新节点;

  • 最后将temp指向新节点。
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

在第i个位置进行插入:分为两种情况,一种是在第1个位置进行插入,另一种为其余所有情况。这种情况是根据循环判断的写法决定的。其他所有情况的解决思想是,找到第i-1个结点,然后在第i个位置进行插入。

  • 在第一个位置插入(采用头插法),可以翻上去看头插法的图,是一样的操作。
  • 其余所有情况。下面举例在第3个位置插入的情况。所下图所示。话就不多说了,思想和头插法是一样的。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述

删除第i个位置结点:同插入一样也是分为两种情况。一种是删除第1个位置的结点,另一种是其他所有情况。

  • 删除第1个位置的情况。如下图。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 其他所有情况。展示删除第二个位置结点的例子,如下图。
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

至于遍历和清空链表的思想比较简单,这里就不画图给大家啦!看着图多会有点复杂,谁当初开始都是这样的,加油!最后再附上程序的输入输出图。
在这里插入图片描述

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值