連載記事カタログ:「アルゴリズムとデータ構造(C言語)」線形リスト ----- リンクリスト http://t.csdn.cn/sL6c6
目次
序文
線形リストは 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のサポートです〜