【アルゴリズムとデータ構造(C言語)】線形リスト ----- 連結リスト

連載記事カタログ:「アルゴリズムとデータ構造(C言語)」線形リスト ----- リンクリスト http://t.csdn.cn/sL6c6

目次

序文

 1. コンセプトと構造

 2. リンクリストの分類

 3. リンクリストの実現 

4. 二重リンクリストの実装

 第二に、シーケンスリストとリンクリストの違い

やっと

要約する



序文

線形リストは 2 つのパートに分かれており、前回は数列テーブルの概念構造とアルゴリズムの実装について説明し、本記事では概念構造、連結リストの分類と関数宣言、および各関数の実現について説明します。

以下の内容は参考用です。批判や修正は大歓迎です~


提示:以下是本篇文章正文内容,下面案例可供参考

 1. 線形リストの連結リスト 

 1. コンセプトと構造

リンク リストは、物理的な記憶構造における非連続かつ非順次の記憶構造であり、データ要素の論理的順序は、リンク リスト内のポインタのリンク順序によって実現されます。

                            

 2. リンクリストの分類

(1) シングルまたは双方向

(2) リードするかリードしないか

(3) 周期的か非周期的か

 3. リンクリストの実現 

// 1、无头+单向+非循环链表增删查改实现
typedef int SLTDateType;
typedef struct SListNode
{
 SLTDateType data;
 struct SListNode* next;
}SListNode;

// 动态申请一个结点
SListNode* BuySListNode(SLTDateType x);

// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);

// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);

// 单链表的尾删
void SListPopBack(SListNode** pplist);

// 单链表头删
void SListPopFront(SListNode** pplist);

// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);

// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode* pos, SLTDateType x);

// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos);

 1.SListNode* BuySListNode(SLTDateType x)

SListNode* BuySListNode(SLTDataType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

 2.void SListPrint(SListNode* plist)

void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		//printf("[%d|%p]->", cur->data, cur->next);
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

 注: typedef キーワードは、データ型 (カスタム データ型 (構造体など) を含む) の新しい名前を定義します。これを使用すると、より複雑な型宣言を簡素化できます。

typedef int SLTDataType;

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

 3.void SLTPushBack(SLTNode** pphead, SLTDataType x)

void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySLTNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		// 找尾
		while (tail->next)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}
}

 4.void SLTPushFront(SLTNode** pphead, SLTDataType x)

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySLTNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

5. void SLTPopBack(SLTNode** pphead)

void SLTPopBack(SLTNode** pphead)
{
	assert(*pphead);

	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}

		free(tail->next);
		tail->next = NULL;
	}
}

6. void SLTPopFront(SLTNode** pphead)

void SLTPopFront(SLTNode** pphead)
{
	assert(*pphead);
	
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

7. SLTNode* SLTFind(SLTNode* phead, SLTDataType x)

SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}

		cur = cur->next;
	}

	return NULL;
}

8. void SLTInsertAfter(SLTNode* pos, SLTDataType x)

void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	
	SLTNode* newnode = BuySLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

9. void SLTEraseAfter(SLTNode* pos)

void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);

	if (pos->next == NULL)
	{
		return;
	}
	else
	{
		SLTNode* nextNode = pos->next;
		//pos->next = pos->next->next;
		pos->next = nextNode->next;
		free(nextNode);
		//nextNode = NULL;
	}
}

4. 二重リンクリストの実装

// 2、带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{
 LTDataType _data;
 struct ListNode* next;
 struct ListNode* prev;
}ListNode;

// 创建返回链表的头结点.
ListNode* ListCreate();

// 双向链表销毁
void ListDestory(ListNode* plist);

// 双向链表打印
void ListPrint(ListNode* plist);

// 双向链表尾插
void ListPushBack(ListNode* plist, LTDataType x);

// 双向链表尾删
void ListPopBack(ListNode* plist);

// 双向链表头插
void ListPushFront(ListNode* plist, LTDataType x);

// 双向链表头删
void ListPopFront(ListNode* plist);

// 双向链表查找
ListNode* ListFind(ListNode* plist, LTDataType x);

// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);

// 双向链表删除pos位置的结点
void ListErase(ListNode* pos);

1. ListNode* ListCreate()

2. void ListDestory(ListNode* plist)

単一リンクリストは参考として使用できますが、ここでは省略します。

3. void LTPrint(LTNode* phead)

void LTPrint(LTNode* phead)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

4. void LTPushBack(LTNode* phead, LTDataType x)

void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* newnode = BuyListNode(x);
	LTNode* tail = phead->prev;

	tail->next = newnode;
	newnode->prev = tail;

	newnode->next = phead;
	phead->prev = newnode;
}

5. void LTPopBack(LTNode* phead)

void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);  


	LTNode* tail = phead->prev;
	LTNode* tailPrev = tail->prev;

	tailPrev->next = phead;
	phead->prev = tailPrev;
	free(tail);
}

6. void LTPushFront(LTNode* phead, LTDataType x)

void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* newnode = BuyListNode(x);
	LTNode* first = phead->next;

	// phead newnode first 
	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = first;
	first->prev = newnode;
}

7. void LTPopFront(LTNode* phead)

void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead); 

	LTErase(phead->next);
}

8. LTNode* LTFind(LTNode* phead, LTDataType x)

LTNode* LTFind(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}

		cur = cur->next;
	}

	return NULL;
}

9. void LTInsert(LTNode* pos, LTDataType x)

void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);

	LTNode* prev = pos->prev;
	LTNode* newnode = BuyListNode(x);
	// prev newnode pos
	prev->next = newnode;
	newnode->prev = prev;
	newnode->next = pos;
	pos->prev = newnode;
}

10. void LTErase(LTNode* pos)

void LTErase(LTNode* pos)
{
	assert(pos);

	LTNode* prev = pos->prev;
	LTNode* next = pos->next;
	free(pos);

	prev->next = next;
	next->prev = prev;
}

 第二に、シーケンスリストとリンクリストの違い

違い

シーケンステーブル

リンクされたリスト

収納スペース

物理的に連続していなければならない

論理的には連続しているが、必ずしも物理的に連続しているとは限らない

ランダムアクセス

O(1) をサポート

サポートされていない: O(N)

任意の位置に要素を挿入または削除する

要素を移動する必要がある場合があり、効率が低い O(N)

ポインタを変更して指すようにするだけです

入れる

ダイナミックシーケンステーブル、スペースが足りない場合は拡張する必要があります

容量の概念がない

アプリケーションシナリオ

要素の効率的な保管 + 頻繁なアクセス

任意の位置での頻繁な挿入と削除

キャッシュの使用率

高い

低い


やっと

幸せな時間はいつも短いです。今日私が話したいのは以上です。この記事では引き続き、シャオ・ジャオ同志のアルゴリズムとデータ構造の連結リスト(C 言語)に関する予備的な認識と実現について簡単に紹介します。家族は批判や修正を歓迎します。Xiao Zhao同志は更新を続けています。継続的な学習の動機は、1つのボタンと3つの連続リンクによるBaoziのサポートです〜

                                                  


おすすめ

転載: blog.csdn.net/weixin_70411664/article/details/128347880