使用GLib集合删除列表中的重复项

时间:2014-08-25 13:49:13

标签: c glib

我的应用可以扫描来自v4l2设备的频率并管理它们。 这有两个功能:

扫描函数并将找到的freq附加到GList * stations

typedef struct {
    GList *stations;
} FreqScanData;

gboolean scan_cb (gpointer data)
{
    static gfloat  freq = FREQ_MIN - 4.0f/STEPS;
    FreqScanData  *fsd = data;

g_assert (fsd);

    if (check_station (freq)) {
        gfloat *f;

        f = g_malloc (sizeof (gfloat));

        *f = freq;
        fsd->stations = g_list_append (fsd->stations, f);
    }

    freq += 1.0/STEPS;

    return TRUE;
}

freq GList * stations附加到现有列表GList * presets的功能:

typedef struct {
{
    GList *presets;
} Settings;

typedef struct Preset preset;
struct Preset
{
    gchar *name;
    gfloat freq;
};

void scan (void)
{
    FreqScanData data;
    Settings settings;
    GList *node;

    for (node = data.stations; node; node = node->next) {
        preset *ps;

        ps = g_malloc0 (sizeof (preset));
        ps->name = g_strdup (_("unnamed"));
        ps->freq = * ((gfloat *) node->data);                       

        settings.presets = g_list_append (settings.presets, ps);
        g_free (node->data);
    }
}

我希望得到这方面的帮助:

如果<{strong> freq找到并附加在data.stations列表中已列入settings.presets列表, 不< / em>再次附加它们。

例如:

找到扫描站列表:

87.50
92.20
101.50
104.50
106.60

和预设列表包含以下内容:

101.50
92.20

- &GT;不要在结果列表中复制它们

1 个答案:

答案 0 :(得分:1)

正如Philip所说,使用哈希表(或树)可能会更好。那就是说,这不是你的问题(我认为,这就是为什么他在评论中建议而不是答案)。

如果您想继续使用链接列表,实际上只有两个选项:每次要插入数据时执行完整扫描,或者保持数据排序,完整扫描成为最差案例,但平均而言,你只需扫描列表的一半。

由于您使用的是g_list_append而不是g_list_prepend,因此您实际上已经进行了完整扫描。为了消除重复,你所要做的就是自己遍历列表直到你到达终点,检查每个值以查看频率是否等于你要插入的频率,如果是,则中止插入。但是,保持预设排序可能会更好,所以......

如果按列表对列表进行排序,则只需遍历列表,检查每个值以查看每个项目的频率是否等于您要插入的频率。如果是这样,则中止插入。如果不是,并且现有项目的频率大于您尝试插入的值,请在当前项目之前插入值。如果频率小于您尝试插入的值,请继续下一个项目。它看起来像这样:

static void preset_free (preset* ps)
{
  g_free (ps->name);
  g_free (ps);
}

static int preset_compare (preset* a, preset* b) {
  if (a->freq < b->freq)
    return -1;
  else if (a->freq > b->freq)
    return 1;
  else
    return 0;
}

static GList* insert_or_ignore_sorted (GList* list, preset* ps, GCompareFunc func) {
  GList* cur = list;
  int cmp_res;

  for (; cur != NULL ; cur = cur->next) {
    cmp_res = preset_compare ((preset*) cur->data, ps);
    if (cmp_res == 0) {
      preset_free (ps);
      return;
    }
    if (cmp_res > 0)
      break;
  }

  return g_list_insert_before (list, cur, ps);
}

void scan (FreqScanData* data)
{
  Settings settings = { NULL };
  GList *node;

  for (node = data->stations; node; node = node->next) {
    preset *ps;

    ps = g_malloc0 (sizeof (preset));
    ps->name = g_strdup (_("unnamed"));
    ps->freq = * ((gfloat *) node->data);

    settings.presets = insert_or_ignore_sorted (settings.presets, ps, (GCompareFunc) preset_compare);
    g_free (node->data);
  }
}