「前の」変数を削除することはできませんが、偽装することはできます。さらに、それが唯一の反復変数になるようにループを構成できます。
もちろん、新しいものを挿入するには、前のノードを更新してそれを指すようにする必要があります。
リストを先読みしてさまざまなケースを処理することにより、現在のノードからそれを行うことができます。
もう 1 つの方法は、前のノードのポインター フィールドへのポインターを保持することです。
node **ppnode;
for (ppnode = &head;
*ppnode != NULL && (*ppnode)->value >= newnode->value;
ppnode = &(*ppnode)->next)
; /* empty body */
newnode->next = (*ppnode) ? (*ppnode)->next : NULL;
*ppnode = newnode;
ここでは、現在のノードを指すポインターを使用する代わりに、現在のノードを間接的に指すポインターcurrent
を使用します。ppnode
そのノードを指す代わりに、そのノードを指すポインターを指します (したがって、適切に入力する必要があります: ポインターへのポインター: 二重星)。
最初のノードへのポインターはリストhead
変数であるため、最初はppnode
その変数を指しhead
ます。その後の他のすべてのノードへのポインターnext
は、前のノードのフィールドです。これらのnext
フィールドのそれぞれhead
は、リストの残りの部分のようです。したがって、この 1 つのppnode
変数を使用して、前のノード自体を追跡することなく、更新する必要がある前のノード内の場所を追跡します。これにより、前のノードがない場合のリストの先頭を処理できます。
head
null の場合 (リストが空)をたどってみましょう。
ppnode
を指しhead
ます。しかし*ppnode
null であるため、ループ本体は実行されません。
ppnode
を指しているためhead
、行は次のとおりです。
newnode->next = (*ppnode) ? (*ppnode)->next : NULL;
*ppnode = newnode;
次と同じ意味です。
newnode->next = head ? head->next : NULL;
head = newnode;
これらの行の条件チェックは、新しいノードが空のリストまたは空でないリストの末尾に追加された場合を処理します。リストが空であるか、その中のすべての値が新しい値よりも小さい場合、ループppnode
はリストの null ターミネータ (head
リストが空の場合)、またはnext
末尾ノードのフィールドを指して終了します。は null であるため*ppnode
、 を参照することはできません(*ppnode)->next
。次はありません。新しいノードは最後のノードであり、next
null にする必要があります。
ここで、ヘッド ノードがあり、その値が大きいため、新しいノードを先頭に挿入する必要がある場合に何が起こるかを見てみましょう。この場合、前と同様に をppnode
指し、条件は true です。ただし、条件が失敗するため、ループは実行されません。head
*ppnode != NULL
(*ppnode)->value >= newnode->value
ここでも、次のコードと同等のコードを実行しています。
newnode->next = head ? head->next : NULL;
head = newnode;
しかし、今回head
は null ではないためnewnode->next = head->next
、以前のようにnewnode
と が新しい になりhead
ます。
他のすべてのケースは、これら 2 つから進行します。ただし、 の代わりに、リストの残りのヘッドのような前のノードhead
のポインターを使用してアクションが実行されます。next