単一リンクリストを数秒で理解する

親愛なる武道の戦士たち、シャオ・アジが今日あなたにもたらしたものを推測しますか?

誰もがそれを推測したに違いありません!

シーケンステーブルを学習した後、リンクリストを学習する必要があります。

まず、シーケンステーブルの欠点を見てみましょう。静的シーケンステーブルについては説明せず、動的シーケンステーブルを見てみましょう。

動的シーケンステーブル:①容量を増やすのに十分なスペースがない場合は、データを挿入します②データを順番に保存する必要があります

欠点:①スペースが足りない場合は、容量を増やす必要があります。容量拡張にはある程度の性能が必要であり、第二に性能の無駄が生じる可能性があります。②ヘッドや中左の挿入・削除効率が低い------> O(n)


それを解決する方法、それから私たちは今日私たちのメインイベントに入る必要があります-リンクリスト

リンクリストの特徴:①空間では、必要に応じて空間を提供する②物理的な空間を連続させる必要がなく、頭と真ん中の挿入と削除でデータを移動する必要がない

概念:リンクリストは、物理ストレージ構造内の非連続および非順次ストレージ構造です。データ要素の論理的な順序は、リンクリスト内のポインターのリンク順序によって実現されます。

論理構造図

 上記の論理構造図から、各ノードがデータとポインターの2つの部分で構成されており、ポインターが次のノードを指していることがわかります。構造タイプとして設定できる各ノード。

物理的構造図:

上記の物理構造図から、最後のノードのポインターがNULLを指していることを除いて、残りのポインターが次のノードのデータフィールドアドレスを指していることがわかります。


 次に、単一リンクリストへの追加、削除、検索などの操作を行います。

私のペースに従ってください!私はすべての勇敢な人々が学んだ後に何かを得ると信じています

 最初にヘッダーファイルを定義します。

#include<stdio.h>
#include<stdlib.h>

#pragma once

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

//打印
void SListPrint(SLTNode* phead);

//尾插
void SListPushBack(SLTNode** pphead, SLTDataType x);

//头插
void SListPushFront(SLTNode** pphead, SLTDataType x);

//头删
void SListPopFront(SLTNode** pphead);

//尾删
void SListPopBack(SLTNode** pphead);

//查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x);
//在pos的前面插入x
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos位置的值
void SListErase(SLTNode** pphead, SLTNode* pos);

このヘッダーファイルには、主に次のものが含まれています。1.ライブラリ関数の宣言2.SLTNodを定義する構造型3.カスタム関数の宣言

.cテストファイルを定義する場合:

#include"SList.h"

void TestSList1()
{
	SLTNode* plist = NULL;
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 4);
	SListPushFront(&plist,5);
	SListPushFront(&plist,6);
	SListPushFront(&plist,7);
	SListPrint(plist);

	SListPopFront(&plist);
	SListPrint(plist);

	SListPopBack(&plist);
	SListPrint(plist);

	//想在3的前面插入一个30
	SLTNode* pos = SListFind(plist, 6);
	if (pos)
	{
		SListInsert(&plist, pos, 10);
	}
	SListPrint(plist);

	pos = SListFind(plist, 10);
	if (pos)
	{
		SListErase(&plist, pos);
	}
	SListPrint(plist);
}

int main()
{
	TestSList1();
	return 0;
}

テストファイル:メイン関数のTestList1を呼び出すことにより、TestList1は最初にSLTNode型の構造体を指す構造体ポインターを定義します。

構造体変数を定義するのではなく、代わりに構造体ポインターを定義する理由を考えてください。

写真が示すように:

 図からわかるように、次のように、ヘッドノードを指すことができる同じタイプの構造ポインターを定義し、ヘッドノードのポインターフィールドを介して2番目のノードにアクセスします。逆に、構造変数はこの効果を達成しません。

次に、ヘッダーファイルにカスタム関数を実装しましょう!

//打印
void SListPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

質疑応答: 

疑問①:これを学ぶと少し混乱しますが、それを取り去らないでください。一部の騎士は、挿入方法や印刷方法さえも学んでいないと思うでしょう!まず第一に、印刷操作は単一リンクリストの他の操作よりも簡単なので、誰もが最初に印刷を受け入れるようにしてください。

疑問②:pheadポインタがヘッドノードのアドレスを指すようにする方法について、誰もが疑問を持っている必要があります。

心配しないでください。挿入について学習すると、pheadポインタがヘッドノードのアドレスをどのように指しているかがわかります。

私に追いついて、プラグインすることを学び始めてください

 

//尾插
void SListPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	newnode->data = x;
	newnode->next = NULL;

	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		//找到尾节点的指针
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		//链接尾节点
		tail->next = newnode;
	}
}

 これを学んだ後、誰もがpheadポインタがヘッドノードをどのように指しているかを知る必要があります!誰もがテール挿入を実装する方法を知っている必要があります!

以下の説明をスキップして、最初にヘッダープラグインを試してから、コードを記述した後、コード内のヘッダープラグインとの違いを確認してください。

//头插
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	newnode->data = x;
	newnode->next = NULL;

	newnode->next = *pphead;
	*pphead = newnode;

}

注:リンクリストが空の場合、新しく追加されたノードのポインターフィールドが空になり、* ppheadも空になります。*ppheadを新しいノードにポイントすると、新しいノードのポインターフィールドが空になり、割り当てます。空、影響しません 

//头删
void SListPopFront(SLTNode** pphead)
{
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

 

//尾删
void SListPopBack(SLTNode** pphead)
{
	//1.空
	if (*pphead == NULL)
	{
		return;
	}
	//2.一个结点
	else if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//3.多个节点,至少两个
	else
	{
		SLTNode* prev = NULL;
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		prev->next = NULL;
	}

}

 

//查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	//while (cur != NULL)
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

 

//在查找的那个数的前面插入x
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	newnode->data = x;
	newnode->next = NULL;

	if (pos == *pphead)
	{
		SListPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = newnode;
		newnode->next = pos;
	}

}

 

//删除pos位置的值
void SListErase(SLTNode** pphead, SLTNode* pos)
{
	//1.为第一个结点或者为空
	if (pos==*pphead)
	{
		SListPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
	
}

 

さて、今日はこれでおしまいです。みんなたくさん学んだと思います!

        続けましょう!

                        次のブログは二重リンクリストです!

QQ:2186529582
わからないことがあれば、遠慮なく追加してください。

 

おすすめ

転載: blog.csdn.net/m0_66488562/article/details/123402883