循環単一リンクリストおよび関連操作の実現

循環単一リンクリスト

不具合がございましたら、訂正させていただきます。やむを得ない間違いがあることは承知しておりますので、ご容赦ください。

以前の単一リンクリストと二重リンクリストの間には、循環リンクリストの3つのリンクリストに対する多くの繰り返しと類似点があります。一般的な論理関係は同じですが、違いは最初のノードと各ノードの関係にあります

単一リンクリスト:各ノードはポインタでリンクされています(方向はhead- > tailです。headノードtailノード-> nextはすべてnullです。  二重リンクリスト:各ノード間に2つのポインタがあります(相互の方向)。ヘッドノード->前ノードテールノード->次は両方ともnullです

(シングルリンクリストとダブルリンクリストは基本的にシングルリンクリストです)

循環リンクリスト:単一リンクリストを完全に再現します。唯一の違いはテールノード-> next = headノードです。

要約すると、循環リンクリストの実現は、テールノードの処理を除いて、単一リンクリストで完全に再現されていることがわかります。

1>単一リンクリストを初期化する

単一リンクリストと同じように、唯一の違いは、ヘッドノードがヘッドストリートを指していることです(最初のテーブルヘッドはヘッドノードとテールノードの両方です

void InitLinkList(LinkList &L)//初始化单链表,强调表所以用LinkList
{
	L = (LNode*)malloc(sizeof(LNode));//为头节点开辟空间
	if (L == NULL)
	{
		printf("为头节点分配空间失败!\n");
	}
	else {
		L->next = L;//初始表头既是头又是尾
		printf("初始化成功\n"); 
	}
}

関数が空のリストかどうかを定義する

void Empty(LinkList L)
{
	if (L->next == L)
		printf("表头为空,分配成功\n");
}

2>リンクリストに値を割り当てます

コードは単一リンクリストと同じですが、唯一の違いは、テールノードが処理され、テールノードが検出され、ポインタがヘッドノードを指すことです。

void CreatList(LinkList &L)//输入数据
{
	LNode *P, *D;//DATA是用来保持每次输入的数据,P的作用是指向单链表尾部
	L = (LNode*)malloc(sizeof(LNode));//创建头节点
	L->next = NULL;//初始化单链表,一开始为空表
	P = L;//空表时头节点也是尾部节点
	int n;//输入数据的个数
	printf("请输入数据的个数:");
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		D = (LinkList)malloc(sizeof(LNode));//给D节点开辟一个空间
		printf("data[%d]=", i);
		scanf("%d", &D->data);//每次输入的数据到D
		D->next = P->next;//第一个节点已经填充,将移动下一个节点
		P->next = D;//D代表的是一个节点,P->next是指向下一个节点
		P = D;
		if (i==n - 1)
		{
			P->next = L;//尾节点指针指向头节点
		}
	}

}

ループ内に判断を追加して、それがテールノードであるかどうかを判断し、それをヘッドノードLにポイントします(割り当てによってダーティデータが上書きされるため、L-> next = NULLが同じかどうかは同じですが、より厳密に書き込まれます)

ループの終わりの判断は判断であることに注意してください(不注意に書かれたいくつか=次のように異なる結果になります)

最初の要素を入力すると、フラッシュバックして直接出力します

 

3>リンクリストの出力

void ShowList(LinkList L)
{
	LNode * P;
	P = (LNode*)malloc(sizeof(LNode));//分配空间
	P = L->next;//单链表从P点开始遍历,等同于从头节点开始
	int i = 0;//记录位序
	printf("打印单链表\n");
	while (P != NULL&&P!=L)//只要节点不为空就可以继续输出
	{
		printf("data[%d]=%d\n", i, P->data);
		i++;
		P = P->next;
	}

出力のロジックは入力のロジックにあります唯一の違いは、処理の最後のステップでテールノードのポインターがテーブルの先頭を指すことです出力ロジックのループ判定条件が変わりつつあります

分析:変数が最後のノードに到達すると、単一リンクリストの判断条件は(node-> next!= null)になり、ノードの次のノードが空の場合、ループから飛び出します。ここで、循環リンクリストの場合、(node-> next!= null)に加えて、最後のノードを判断する必要があります。ノードのトラバーサルはP = P-> nextであるため、ダイナミックによってポイントされる次のノード毎回ノードが次のノードです。

個人的な経験:初めて書いたとき、判断条件にP-> next!= Lを追加しました。問題ないようですが、ループ内のコード(P = P-> next)がテールノードからヘッドノード(L)までなので、このように判断すると、出力に問題が発生し、テールノードが1つ少なくなります(下図のエラーコードの出力)。

4>リンクリストで検索

単一リンクリスト:ノードを基準にして検索すると、ランダムクエリの特性がないため、ヘッドノードからノード全体をトラバースして必要なノードを見つけることしかできません。

二重リンクリスト:同じ原則とプロパティはよく理解されていますが、ノードの先行ノードで処理できない単一リンクリストとは異なり、二重リンクリストの方が柔軟性が高くなります。たとえば、(iノードとi +を削除する) 2ノードとi-2ノードを同時に)、シングルリンクリスト処理の場合は複数回トラバースする必要があります(一度に実行することもできますが、より面倒で複数の判断ノードが必要です)。リンクリストを解決するために必要なトラバーサルは1つだけです。さまざまな環境に適用でき、それぞれに独自の特性があります

循環リンクリスト:すべてのノード削除する必要があるが、ノードが削除されてテールノードになるたびに、このような状況では、単一リンクリストと二重リンクリストが1回削除され、1回トラバースされるため、無駄になります。多くの時間とリソース。しかし、循環リンクリストはこの問題を解決できます。ヘッドとテールの処理が頻繁に行われる場合、ポインタはテールノードを直接指すことができます(テールノード->次はヘッドノードです)。これにより、多くの時間とリソースを節約できます。しかし、それは状況に依存します、ここに通常の検索要素があります

void GetElem(LinkList L, int i)
{
	if (i < 0)
		printf("查询位置不合法");
	else {
		LNode* P;//创建一个记录节点的指针
		int number = 1;//记录查询到几个节点
		P = L->next;//指向头节点,从头节点开始查询变量
		if (i == 0)
			printf("头节点为空");//头节点不存放数据
		while (P != NULL && number < i)
		{
			P = P->next;//寻找到第i节点
			number++;
			if (P->next ==L)
			{
				P->next = L->next;
			}
		}
		printf("查询第%d个元素为%d\n", i, P->data);
	}

}

ビット単位の検索は、基本的に単一リンクリストのビット単位の検索と同じです。ここでは、循環リンクリストを反映するようにテールノード処理しましテールノードで判断することができます。テールノードをトラバースすると、ポインタは最初のノード(ヘッドノードの後の最初のノード)を指すことができます。実際、この方法は、の合法性を判断するためにも使用できます。挿入位置。リスト内のクエリ要素がケースの長さを取得しない場合、ノードはクエリを出力することもできます(クエリリストの範囲を超えない)が、これは一挙に繰り返されます。高可用性の共感のリストの長さに直接アクセスすることはできません

同様に、値によるクエリの原則は、ここでは省略されている単一リンクリストの原則と同じです。

5>リンクリストからデータを削除する

削除データコードは単一リンクリストと一致しており、エピトープでの処理は、i-1ノードがLを指すようにするだけで済みます p-> next = q-> next; )はすでに暗示されています

i番目の要素を削除します

手順:最初にi-1番目のノードを見つける必要があります-> i-1ノードがテールノードであるかどうかを判断します(はい:ノードを削除してリンクリストに含まれていません、いいえ:i番目のノードを削除します)- >ノードの後のi番目のノードを削除します(i-1ノードをヘッドノードにポイントし、iノードを解放します)

void ListDelet(LinkList &L, int i)
{
	if (i < 1)
		printf("删除位置不合法");
	LNode *p;//用来指向查询元素的指针
	int number = 0;//记录节点的位置
	int e=0;//用来保存删除数据
	p = L;//查询节点应从头开始,所以指向头节点
	while (p != NULL && number < i - 1)
	{
		p = p->next;//只是寻找到第i-1节点
		number++;
	}
	if (p == NULL)//这里是说明了i-1是尾节点
	{
		printf("删除内容为空");
	}
	else {
		LNode*q = p->next;
		e = q->data;//记录删除的数据
		if (q->next = L)
		{
			p->next = L;
			free(q);//释放掉该节点
		}
		else {
			p->next = q->next;
			free(q);//释放掉该节点
		}
		printf("删除第%d节点元素%d成功\n", i, e);
	}
		
}

6>全体的なコード

#include<stdio.h>
#include<stdlib.h>
typedef struct LNode
{
	int data;//保存每个节点数据的变量
	struct LNode *next;//指向下一个节点的指针
}LNode,*LinkList;

void InitLinkList(LinkList &L)//初始化单链表,强调表所以用LinkList
{
	L = (LNode*)malloc(sizeof(LNode));//为头节点开辟空间
	if (L == NULL)
	{
		printf("为头节点分配空间失败!\n");
	}
	else {
		L->next = L;//初始表头既是头又是尾
		printf("初始化成功\n"); 
	}
}

void Empty(LinkList L)//检查表是否为空
{
	if (L->next == L)
		printf("表头为空,分配成功\n");
}

void CreatList(LinkList &L)//输入数据
{
	LNode *P, *D;//DATA是用来保持每次输入的数据,P的作用是指向单链表尾部
	L = (LNode*)malloc(sizeof(LNode));//创建头节点
	L->next = NULL;//初始化单链表,一开始为空表
	P = L;//空表时头节点也是尾部节点
	int n;//输入数据的个数
	printf("请输入数据的个数:");
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		D = (LinkList)malloc(sizeof(LNode));//给D节点开辟一个空间
		printf("data[%d]=", i);
		scanf("%d", &D->data);//每次输入的数据到D
		D->next = P->next;//第一个节点已经填充,将移动下一个节点
		P->next = D;//D代表的是一个节点,P->next是指向下一个节点
		P = D;
		if (i==n - 1)
		{
			P->next = L;//尾节点指针指向头节点
		}
	}

}


void GetElem(LinkList L, int i)
{
	if (i < 0)
		printf("查询位置不合法");
	else {
		LNode* P;//创建一个记录节点的指针
		int number = 1;//记录查询到几个节点
		P = L->next;//指向头节点,从头节点开始查询变量
		if (i == 0)
			printf("头节点为空");//头节点不存放数据
		while (P != NULL && number < i)
		{
			P = P->next;//寻找到第i节点
			number++;
			if (P->next ==L)
			{
				P->next = L->next;
			}
		}
		printf("查询第%d个元素为%d\n", i, P->data);
	}

}

void ListDelet(LinkList &L, int i)
{
	if (i < 1)
		printf("删除位置不合法");
	LNode *p;//用来指向查询元素的指针
	int number = 0;//记录节点的位置
	int e = 0;//用来保存删除数据
	p = L;//查询节点应从头开始,所以指向头节点
	while (p != NULL && number < i - 1)
	{
		p = p->next;//只是寻找到第i-1节点
		number++;
	}
	if (p == NULL)//这里是说明了i-1是尾节点
		printf("删除内容为空");
	LNode*q = p->next;
	e = q->data;//记录删除的数据
	if (p->next->next = L)
	{
		p->next = L;
		free(q);//释放掉该节点
	}
	else {
		p->next = q->next;
		free(q);//释放掉该节点
	}
	printf("删除第%d节点元素%d成功\n", i, e);
}

void ShowList(LinkList L)
{
	LNode * P;
	P = (LNode*)malloc(sizeof(LNode));//分配空间
	P = L->next;//单链表从P点开始遍历,等同于从头节点开始
	int i = 0;//记录位序
	printf("打印单链表\n");
	while (P != NULL&&P!=L)//只要节点不为空就可以继续输出
	{
		printf("data[%d]=%d\n", i, P->data);
		i++;
		P = P->next;
	}
}
		



void main()
{
	LinkList L;//创建一个单链表
	InitLinkList(L);//初始化
	Empty( L);//判断是否为空
	CreatList(L);//输入数据
	GetElem(L, 7);//查询数据(按位)
	ListDelet(L, 5);
	ShowList(L);//输出数据

}

 

おすすめ

転載: blog.csdn.net/qq_46861651/article/details/112861145