リンクリストの最初の章

ここに画像の説明を挿入します

私の世界へようこそ

コレクション列:リンクされたリスト

著者の記事があなたのお役に立てば幸いです。不備があれば修正してください。一緒に学び、コミュニケーションをとりましょう。


序文

  • ここに書いているのは、リンクリストの罠に陥ったことについての質問です。私が罠にはまるまでの過程を詳しく書きました。皆さんも罠にはまったことがあると思います。このコラムは今後も更新していきます。 ご協力ありがとうございます。
    ————————過程に全力を注ぎ、結果には無頓着である

質問 1: リンクされたリストの最後から n 番目のノードを削除します。


住所:ojタイトルアドレス


ここに画像の説明を挿入します

問題解決のアイデア:

  • 1. 暴力的なトラバーサル:
    最初に 1 回トラバースしてリンク リストにノードがいくつあるかを見つけます (最初のトラバーサル)。次に 2 回目のトラバースで最後から n 番目のノードを見つけて削除し、元のアドレスに戻ります。この方法は、この質問に対して比較的簡単な実装方法であると言えます。ここで別の方法について話したいと思います。

  • 2. 3 ポインタ方式:
    まず、tail ポインタ、sur ポインタ、および dst ポインタの 3 つのポインタを作成します。sur ポインタと dst ポインタは、最初はリンク リストの開始アドレスを指し、テール ポインタはその前のバイトのアドレスを指します。 sur ポインタ これは、
    次の最初の物理図で sur のアドレスが見つかるスペースを再度開く必要がありますここに画像の説明を挿入します
    注: リンク リストのアドレスは接続されていないため、アドレスはランダムであるとみなすことができます。写真内のアドレスは、便宜と観察を容易にするために、すべて私がランダムにまとめたものです。

  • アイデア: まず、dst ポインタを n ノード後方に移動させて、dst ポインタと sur ポインタが n ノード離れるようにします。次に、dst ポインタが null ポインタを指すまで、これら 3 つのポインタを一度に 1 ノードずつ後方に移動させます。その場合、 sur は下から n 番目のノードを指します (このステップの概念は非常に重要であり、明確に考える必要があります)このとき、削除されるノードのアドレスがあり、また、削除されるノードのアドレスもあります。末尾ポインタが指すノードの上のノードを削除すると、削除は非常にうまく完了できます。
    上記はアイデアです。以下でそれを実装してみましょう

最後に物理図:
ここに画像の説明を挿入します

struct ListNode* removeNthFromEnd(struct ListNode* head, int n ) {
    
    
    // write code here

    //sur指针是指向要删除的那个节点,dst是与sur保持间距n的,tail是sur前一个节点
    struct ListNode* sur = head, *dst = head;
    struct ListNode*tail =(struct ListNode*)malloc(sizeof(struct ListNode));
    tail->next=sur;
    //先让dst指针走n个节点
    while (n--) {
    
    
        dst = dst->next;
    }
    while (dst) {
    
    
        //三个指针一起出发,tail指针始终指向sur指针前前一个节点 
        dst = dst->next;
        sur = sur->next;
        tail = tail->next;

    }
    //删除
    if (head == sur) {
    
    
        //如果sur没动说明要删的就在第一个
        head = head->next;
        sur = head->next;
    } else {
    
    
        //要删的只要找到sur指针的前一个节点,就可以让sur后一个节点与之相连
        tail->next = sur->next;
    }
    return head;
}

質問 2: リンク リストの中間ノード


住所:ojアドレス


ここに画像の説明を挿入します
問題解決のアイデア:

  • 1. 暴力的な走査方法:
    この質問の通常の考え方によれば、まずリンク リスト内のすべてのノードの数を走査し、次に中間点を取得し、最後にその点を指すアドレスを返す必要があります。この方法は次のとおりです。非常に一般的なので、ここでは詳しく説明しませんが、次の方法について詳しく説明したいと思います。
  • 2.高速ポインタ方式と低速ポインタ方式:
    このメソッドのアイデアは次のとおりです: まず、2 つのポインターを設定します: それぞれ高速ポインターと低速ポインターです。まず、両方のポインターはリンクされたリストの開始位置を指し、低速で次のノードに移動し、高速で移動します。次の 2 つのノードに移動します。高速ポインタが停止するまで、高速ポインタはいつ停止しますか?さまざまな状況があるはずです。リンクされたリストのノードが偶数の場合、高速は空になるまで移動します。リンクリストのサマリーポイントが奇数の場合、高速に終了点で停止します。
    ----奇数の場合: ロジック図:
    第 1 ステップ:ここに画像の説明を挿入します
    第 2 ステップ:
    ここに画像の説明を挿入します
    第 3 ステップ
    ここに画像の説明を挿入します

偶数の場合:
ロジック図:
第 1 ステップ:ここに画像の説明を挿入します
第 2 ステップ:
ここに画像の説明を挿入します
第 3 ステップ:
ここに画像の説明を挿入します
第 4 ステップ:
ここに画像の説明を挿入します

コード:

struct ListNode* middleNode(struct ListNode* head ) {
    
    
    // write code here
	//设置快慢指针
    struct ListNode*sur=head,*dst=head;
	//当dst指针为空或dst指向的next为空就停下
    while(dst && dst->next)
    {
    
    
        sur=sur->next;
        dst=dst->next->next;
    }
	
    return sur;
}

質問 3: 2 つの並べ替えられたリンク リストを結合します。


住所:ojアドレス


ここに画像の説明を挿入します
問題解決のアイデア:

まず第一に、リンク リストはシーケンシャル リストとは異なり、機能しないアイデアもあります。しかし、利点もあります。リンク リストは一度に 1 つのノードに接続されており、いつでも解体できます。マージ メソッドを使用すると、次のことができます。まず 2 つのポインタを作成し、
マージする必要がある 2 つのリンク リストのセットを開始位置から比較します。ポインタは小さい方の値の末尾に挿入され、もう 1 つのポインタはマージする必要がある前のノードを検索します。尾部の挿入を容易にするために挿入される。
ここに画像の説明を挿入します
1<2 を比較し、末尾に 1 を挿入します。最初の挿入の場合、先頭ポインタと末尾ポインタは同時に 1 のアドレスを指す必要があります。最初の挿入でない場合は、Head1 のアドレスを指します。を tail->next に与え、次にテールポインタが tail->next を指すようにし、最後に pHead1 が次のノードを指すようにします。
ここに画像の説明を挿入します

  • 2<3 の場合、最後に 2 のアドレスを挿入します。上記の手順と同じです。
    注: これは、このポイントの後の最初の挿入ではありません。末尾ポインタが末尾の次のノードを指すようにすることを忘れないでください。

    ここに画像の説明を挿入します
    以下の手順はほぼ同じで、
    リンク リストが 1 つなくなるまで、残りのリンク リストの末尾を直接挿入し、最後に先頭のポインタを返し、最後に
    ここに画像の説明を挿入します
    ここに画像の説明を挿入します
    先頭のポインタを返します。
    しかし、これは正しいでしょうか?
    いいえ、もう 1 つの手順を忘れていました。2 つのリンク リストの一方が空の場合、このプログラムの結果は間違いなくエラーを報告するため、最初に判断する必要があります。2 つのリンク リストの一方が空の場合; その後、他のリンクされたリストに直接戻ります。

コード:

struct ListNode* Merge(struct ListNode* pHead1, struct ListNode* pHead2 ) {
    
    
    // write code here
    //如果其中一个链表为空,则直接返回另一个链表
    if(pHead1==NULL)
        return pHead2;
    if(pHead2==NULL)
        return pHead1;
         
    struct ListNode* head = NULL, *tail = NULL;
    //判断哪个链表先为空,就跳出去
    while (pHead1 && pHead2) {
    
    
        if (pHead1->val < pHead2->val) {
    
    
            if (tail == NULL) {
    
    
                //第一次尾插
                head = tail = pHead1;
                
            } else {
    
    
                //不是第一次尾插
                tail->next = pHead1;
                tail=tail->next;
                
            }
            //让篇pHead1指针找到下一个结点
            pHead1 = pHead1->next;
            
        } else {
    
    
            if (tail == NULL) {
    
    
                //第一次尾插
                head = tail = pHead2;
            } else {
    
    
                //不是第一次尾插
                tail->next = pHead2;
                tail=tail->next;
            }
            //让篇pHead2指针找到下一个结点
            pHead2 = pHead2->next;
        }
    }
    //判断哪个链表先为空,然后让另一个链表直接尾插入;
if(pHead1)
    tail->next=pHead1;

if(pHead2)
    tail->next=pHead2;

    return head;
}

要約する

ここで、見守ってくださった退役軍人の方々に感謝したいと思います。そして、ここで子供たちから、サポートしてくれた皆さんに感謝したいと思います。上記の質問は、子供たちの現在の能力に基づいています。より良い方法がある場合は、話し合いの場で一緒に話し合うことができます。コメントエリア. 将来的には、子供の知識の蓄えが増えるにつれて、子供は間違いなくそれを最適化するでしょう!


最後に、
これだけは言っておきたいのですが、
----------過程に全力で取り組み、結果には無関心であれ、これは
私が自分に言い聞かせていることでもあります。

おすすめ

転載: blog.csdn.net/m0_66780695/article/details/132279076