あなたの質問はすでに答えられていますが、私が誰かにインタビューしていて、彼らがこのようにコードを書いたとしても、私はそれほど感銘を受けないだろうと指摘しなければなりません。
手始めに、ここでのポインターへのポインターの使用は、Cでは妥当ですが、C++では完全に不要です。代わりに、ポインターへの参照を表示したいと思います。第二に、constが正しいコードが一般的に望ましいです。
bool deleteElement(IntElement const *&head, IntElement const *deleteMe)
{
IntElement *elem = head;
if(deleteMe == head){ /*special case for head*/
head = elem->next;
delete deleteMe;
return true;
}
while (elem){
if(elem->next == deleteMe){
/*elem is element preceding deleteMe */
elem->next = deleteMe->next;
delete deleteMe;
return true;
}
elem = elem->next;
}
/*deleteMe not found */
return false;
}
最後に、リストの不要なトラバースを回避するために、もう1つの特殊なケースを追加します。削除するアイテムがたまたまリストの最後にない限り、トラバーサルを回避できます。IntElementが次のようなものであると仮定しましょう。
struct IntElement {
int data;
IntElement *next;
};
この場合:
bool simple_delete(IntElement *deleteMe) {
IntElement *temp = deleteMe->next;
deleteMe->data = temp->data;
deleteMe->next = temp->next;
delete temp;
return true;
}
リスト全体を検索して前の要素を見つけているので、後の要素を削除できます。代わりに、次のノードを現在のノードにコピーしてから、次のノードを削除します(注:コピーするよりもデータを交換する方が良い/速い場合があります)。また、他の何かが次のノードへのポインタを保持している可能性がある場合、これは物事を(かなり完全に)壊す可能性があることにも注意してください。
[その価値については、私はもともと、この手法をニクラウスヴィルトによるアルゴリズム+データ構造=プログラムから学びましたが、クヌースに端を発していると思います。]
deleteElement
とにかく、それができたら、削除するノードがリストの最後でない限り、それを使用するためのコードを少し追加するだけです。
bool deleteElement(IntElement const *&head, IntElement *deleteMe) {
if (deleteMe->next != NULL)
return simple_delete(deleteMe);
// previous body of deleteElement
}
オリジナルが常に線形の複雑さを持っていた場合、これはほとんどの場合一定の複雑さを持っています。最後にNULLポインターの代わりに番兵値を持つリストを使用することにより、すべての場合で一定の複雑さを保証できます(そして、すべてのsimple_delete
場合を処理します-残りのコードを完全に排除できます)。