【解決方法】C のリンクされたリストで隣接する重複を削除する際の小さなバグの修正に役立ちます


目標は、リンクされたリスト内の隣接する重複を削除することです。 たとえば、入力 aaabccf は bccf (隣接する重複 a を削除) —> bf (隣接する重複 c を削除) に縮小され、出力は bf になります。 入力が aaa の場合、出力は NULL です。

私のCコードは、削除される隣接する重複ノードの1つが最後にあり、NULLを指す aaa 、 abb 、 aabcdd などの場合を除いて、ほとんどの場合に正常に機能します。 どこを間違えたのか教えてください。

私が試したこと:

これは、隣接する重複を削除するための私のコードです-

void remove_adj_dup(struct node** head)
{
    struct node *temp=NULL, *current=NULL, *temp2=NULL;
    int flag=1;

    while(flag)
    {
        current = *head;
        flag=0;

        while(current->next!=NULL)
        {
            if(current->data==current->next->data)
            {
                temp=current;
                flag=1;
                while(current->data==current->next->data && current->next!=NULL)
                {
                    current=current->next;
                }
                
                if(temp== *head) *head=current->next;
                
                else
                {
                    temp2= *head;
                    while(temp2->next!=temp) temp2=temp2->next;
                    temp2->next=current->next;
                }
                //printf("# %c\n",current->next->data);
                //printList(*head); 
            }
            
            current=current->next;
        }
    }
}

解決策 2

関数 remove_adj_dup() には、null ポインターがアクセスされる場所がいくつかあります。 最初に、可変ヘッドをチェックすることは理にかなっています。

if ((head == NULL) || (*head == NULL))
  return;

ヌル ポインターで問題が発生する場所がさらに 2 つあります。

//while (current->next != NULL)
while ((current != NULL ) && (current->next != NULL))

current->next をチェックする前に、 current が null ポインターでないことも確認する必要があります。 デバッガーを使って練習するために、もう 1 つの場所を残します。
フラグは不要であり、対応する while ループと同様に完全に削除できます。

current = *head;
// while (flag)
// {
//   flag = 0;

解決策 1

コンパイルしても、コードが正しいとは限りません! :笑う:
開発プロセスは電子メールを書くことと考えてください。コンパイルが成功したということは、電子メールを適切な言語 (たとえば、ドイツ語ではなく英語) で作成したことを意味します。電子メールに送信したいメッセージが含まれていたわけではありません。

これで、開発の第 2 段階に入ります (実際には第 4 段階または第 5 段階ですが、後で前の段階に進みます): テストとデバッグです。

それが何をするのか、そしてそれがあなたが望んでいたものとどのように違うのかを見ることから始めてください。 これは、なぜそれを行っているのかについての情報を提供するため、重要です。 たとえば、プログラムがユーザーに数字を入力させることを目的としており、それを2倍にして答えを出力する場合、入力/出力が次のようになると:

Input   Expected output    Actual output
  1            2                 1
  2            4                 4
  3            6                 9
  4            8                16

次に、問題がそれを2倍にするビットにあることは明らかです-それ自体を加算したり、2倍したりするのではなく、それ自体を乗算して入力の2乗を返します。
それで、コードを見ることができ、それがここのどこかにあることは明らかです:

int Double(int value)
   {
   return value * value;
   }

何がうまくいかないのかがわかったら、デバッガーを使用して原因を突き止めます。 メソッドの最初の行にブレークポイントを置き、アプリを実行します。 ブレークポイントに到達すると、デバッガーが停止し、制御がユーザーに渡されます。 コードを行ごとに実行し (「シングル ステップ」と呼ばれます)、必要に応じて変数の内容を確認 (または変更) できるようになりました (コードを変更して、必要に応じて再試行することもできます)。
コードを実行する前に、コードの各行が何をすべきかを考え、「ステップ オーバー」ボタンを使用して各行を順番に実行したときに実際に何をしたかを比較します。 それはあなたが期待したことをしましたか? その場合は、次の行に進みます。
そうでない場合、なぜですか? どう違うの?
うまくいけば、そのコードのどの部分に問題があり、何が問題なのかを突き止めるのに役立つはずです。
これはスキルであり、開発だけでなく現実の世界でも役立つため、開発する価値のあるスキルです。 そして、すべてのスキルと同様に、それは使用することによってのみ向上します!

コメント

タイトルとURLをコピーしました