探討兩種迴圈表示方法的區別,while迴圈與for迴圈的小總結

Rice_rice發表於2024-04-23

基於前天建立的順序表(sequeue)的其中一個功能函式,引出兩個迴圈的表示方法的區別和比較。

演算法需求:在一個順序佇列中,合併相同的元素。

總體思路:利用兩層迴圈的框架,利用外層迴圈選中順序表中第一個數(L->data[i]),再用內迴圈中進行對比(L->data[j]),如果相同就進行刪除操作。

首先採用for迴圈:

int list_purge(sqlink L)
{
    int i = 1;
    int j;
    if (L->last == 0)//如果順序表內只有一個函式,則無重複元素直接返回。
        return 0;
        for (i = 1; i <= L->last; i++)//外層迴圈,選取順序表中一個數值
    {
        for (j = i - 1; j >= 0; j--)//內層迴圈,將外層迴圈的數值依次與i-1以內的數值進行比較
        {
            if (L->data[i] == L->data[j])//若出現相同的情況,則進行刪除操作
            {
                list_delete(L, i);
                break;
            }
        }
    }
    }

​ 為減少功能函式間的耦合,用了獨立的刪除功能函式,具體可見另一篇《基於C語言的順序表的建立,及各類功能函式實現》,因不是重點,不討論該函式。

​ 該演算法較為簡單,能實現基本功能。但有一個非常致命的問題:當出現連續三個需要操作的元素,無法連續刪除其中兩個。利用簡單的幾個數字測試,結果示例如下:

int main(int argc, const char *argv[])
{
    sqlink L;
    L = list_create();
    list_insert(L, 10, 0);
    list_insert(L, 20, 0);
    list_insert(L, 30, 0);
    list_insert(L, 20, 0);
    list_insert(L, 30, 0);
    list_show(L);
    list_purge(L);
    list_show(L);
    return 0;
}

執行結果:

​ 為方便分析,編寫陣列來說明,arr[0]=30;arr[1]=20;arr[2]=30;arr[3]=20;arr[4]=10;

​ 在第一輪迴圈中,arr[1]!=arr[0],沒有相同元素。

​ 在第二輪迴圈中,arr[2]!=arr[1],arr[2] == arr[0],執行刪除操作,刪除之後變成了:arr[0]=30;arr[1]=20;arr[2]=20;arr[3]=10;即是在刪除第一個相同元素後,整體元素往前移動。

​ 在第三輪迴圈中,arr[3]!=arr[2],arr[3]!=arr[1],arr[3] != arr[0],即第三輪無法將改變後的a[2]與a[1]進行比較,因此出現執行結果的錯誤。


因此,考慮採用while迴圈最佳化:

int list_purge(sqlink L)
{
    int i = 1;
    int j;
    if (L->last == 0)//如果順序表內只有一個函式,則無重複元素直接返回。
        return 0;
    while (i <= L->last)//外層迴圈,選取順序表中一個數值
    {
        j = i - 1;
        while (j >= 0)
        {
            if (L->data[i] == L->data[j])//內層迴圈,將外層迴圈的數值依次與i-1以內的數值進行比較
            {
                list_delete(L, i);//若出現相同的情況,則進行刪除操作
                break;
            }
            else
                j--;
            if (j < 0)
                i++;
        }
    }

​ 分析如下,arr[0]=30;arr[1]=20;arr[2]=30;arr[3]=20;arr[4]=10:

​ 在第一輪迴圈中,arr[1]!=arr[0],沒有相同元素。

​ 在第二輪迴圈中,arr[2]!=arr[1],arr[2] == arr[0],執行刪除操作,刪除之後變成了:arr[0]=30;arr[1]=20;arr[2]=20;arr[3]=10;整體元素往前移動。

​ 將遍歷指數j和i都放進內迴圈,導致的直接結果是,當進行list_delete(L, i)操作後,透過“break”退出內迴圈,會重新進行比較,成功解決了重複元素無法刪除的問題。

​ 因此執行結果如下:

...

​ 透過這個例子,可較直接理解while與for迴圈的區別,即在遍歷過程中,for的末尾迴圈體(increment)會直接需要應用在下次迴圈,而while可在遍歷過程結束之後才進行increment操作。總結一句話就是:while遍歷更充分。

​ 記錄在此供參考學習,如有不足之處,敬請批評指標,歡迎交流。

相關文章