2012-06-03 105 views
2

我有兩個列表。有沒有簡單的方法從數組中刪除項目?

char *name[] = {"RGS", "O", "NRGY", "SIG", "BML-O", "BHI", "KSU", "ORN"}; 
char *name_to_remove[] = {"RGS", "O", "NRGY"}; 

有沒有一種有效的方法來獲取項目列表並從另一個列表中刪除它?我已經實現了我自己的版本,但我認爲它效率很低。它基本上製作了一個名稱列表的副本,然後使用一個嵌套for循環,通過重複名稱& name_to_remove列表並標記任何重複「刪除」的項目。最後,我瀏覽列表並複製除了值爲'remove'的項目之外的所有項目。它可怕的醜陋,我懷疑效率低下。我有麻煩的問題(之前沒有處理過)是我不確定如果它可能從數組中刪除一個項目,如果該數組是一個固定大小的內存,所以我最初試圖改變值,然後將這些值添加到新數組中(與原始大小相同 - 我想要移除的項目數組的大小)。

我看不到更好的方式來做到這一點,似乎memcmp有前途的,因爲它可以比較兩個列表,但我一直無法理解它如何適應。我知道C不是蟒蛇,但這裏是我如何做到這一點乾淨的python:

for item in name_to_remove: 
    name_copy.remove(item) 

也許場景下,python命令是做盡可能多的圈,因爲我做什麼,但我認爲我會問。

回答

2

答案是使用適當的數據結構。 Python列表絕對不是作爲純C字符串數組實現的(僅僅因爲你可以在Python列表中存儲不同類型的對象)。所以你要查找的數據結構可能是linked listhash table

+0

如何將一個鏈表是有用的嗎? – goat

+1

@chris因爲如果'name'是一個鏈表,你可以釋放()需要刪除的節點(並將前一個節點的「next」指針重新指向下一個節點)。但是,鏈表的開銷是否值得,完全取決於你需要多久修改一次(中途)列表/數組。根據情況,動態數組或純靜態數組可能是更好的選擇。 – Will

0

你可以製作一個散列圖,然後遍歷一個數組並通過mapOfRemovableWords.contains(words[i])進行測試,並使用它來決定是否應該將該元素複製到新數組(或其前面)。

你也可以兩個數組排序,然後通過他們在同一時間進行迭代。使用這樣一個事實,如果您處於某個單詞大於另一個列表中的當前單詞的位置,則它不在另一個列表中。你迭代一個,然後決定是否需要迭代另一個,並重復,直到完全通過兩者。

0

我想象的Python版本並不比你的代碼更有效。

這就是說,你肯定能提高您的實現。請記住,C數組實際上只是一個內存塊,有一堆指向字符串開頭的指針。既然你沒有創建新的字符串,你總是可以重用字符串指針。

概念,循環在你的陣列,設置指針爲空值是否在列表中刪除。然後使用malloc()創建一個適當大小的新數組。循環訪問舊數組,將非空指針複製到新數組。

這種方式,你已經有了2次循環迭代和單一的malloc。

1

它基本上使得名單的副本,然後使用嵌套的for循環,通過這兩個名稱重複& name_to_remove名單去,並標誌着重複在「刪除」的任何項目。最後,我瀏覽列表並複製除了值爲'remove'的項目之外的所有項目。

而是標誌着什麼的,你可以只複製您發現任何項目namename_to_remove沒有並將其存儲在一個新的數組,然後垃圾舊name陣列。

0

如果您在編譯時分配第一個數組,那麼它的大小是固定的,我相信通過「刪除」選定的元素將不可能隨後回收任何內存。我建議要麼實現一個可以動態分配的鏈接列表,並且隨後要刪除一個項目,或者更好的是,更有效的數據結構(如二進制搜索樹)。

1

如果字符串的順序並不重要,你既可以陣列排序,找到重複,像這樣:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define ARR_SIZE(array) sizeof(array)/sizeof(const char *) 

int compare (const void * a, const void * b) { 
    return strcmp(*((const char**)a), *((const char**)b)); 
} 

int main(void) { 
    const char *name[] = {"RGS", "O", "NRGY", "SIG", "BML-O", "BHI", "KSU", "ORN"}; 
    const char *name_to_remove[] = {"RGS", "O", "NRGY"}; 
    int i = 0, j = 0; 
    qsort(name, ARR_SIZE(name), sizeof(const char*), compare); 
    qsort(name_to_remove, ARR_SIZE(name_to_remove), sizeof(const char*), compare); 
    while (i != ARR_SIZE(name) && j != ARR_SIZE(name_to_remove)) { 
      int diff = strcmp(name[i], name_to_remove[j]); 
      if (diff == 0) { 
        name[i] = NULL; 
        i++; 
        j++; 
      } else if (diff < 0) { 
        i++; 
      } else { 
        j++; 
      } 
    } 
    for (i = 0 ; i != ARR_SIZE(name) ; i++) 
      if (name[i]) 
        printf("%s\n", name[i]); 
    return 0; 
} 
+0

如果你真的想保持數組的排序,這個解決方案很好,但如果你只關心刪除匹配元素,我希望大家都清楚這是非常低效的。 – Will

+0

@WillBuddha這個解決方案是'O(N * logN)' - 比OP的'O(N^2)'更高效。 – dasblinkenlight

+0

不,即使在最天真的情況下,用於刪除的雙循環不是O(N^2)而是O(N * M),其中M Will

相關問題