日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

glib 队列

發(fā)布時(shí)間:2025/3/8 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 glib 队列 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址: http://hi.baidu.com/study_together/blog/item/b92d822ef2589e39349bf79c.html

編譯:gcc -g -Wall -O0 fuck.c -o fuck `pkg-config --libs --cflags glib-2.0`

概念

隊(duì)列是另一個(gè)便利的數(shù)據(jù)結(jié)構(gòu)。一個(gè) 隊(duì)列 會(huì)保存一列條目,而且訪問(wèn)形式通常是向最后添加條目,從最前刪除條目。

當(dāng)需要按到達(dá)順序進(jìn)行處理時(shí),這很有實(shí)用。標(biāo)準(zhǔn)隊(duì)列的一個(gè)變種是“雙端隊(duì)列(double-ended queue)”,或者說(shuō)是 dequeue,

它支持在隊(duì)列的兩端進(jìn)行添加或者刪除。

不過(guò),在很多情況下最好避免使用隊(duì)列。隊(duì)列搜索不是特別快(是 O(n) 操作),所以,如果需要經(jīng)常進(jìn)行搜索,那么散列表或者樹(shù) 可能更實(shí)用。

這同樣適用于需要訪問(wèn)隊(duì)列中隨機(jī)元素的情形;如果是那樣,那么將會(huì)對(duì)隊(duì)列進(jìn)行很多次線性掃描。

GLib 提供了一個(gè)使用 GQueue 的 dequeue 實(shí)現(xiàn);它支持標(biāo)準(zhǔn)隊(duì)列操作。它的基礎(chǔ)是雙向鏈表(GList), 所以它也支持很多其他操作,

比如在隊(duì)列之中進(jìn)行插入和刪除。不過(guò),如果您發(fā)現(xiàn)自己經(jīng)常要使用這些功能,那么可能需要重新考慮容器的選擇; 或許另一個(gè)容器更為合適。


1
基本操作

這里是以“排隊(duì)買票(ticket line)”為模型的一些基本的 GQueue 操作:

#include <glib.h>
#include
<stdio.h>

int main(int argc, char** argv) {
GQueue
* q = g_queue_new();
printf(
"Is the queue empty? %s, adding folks\n", g_queue_is_empty(q) ? "Yes" : "No");
g_queue_push_tail(q,
"Alice");
g_queue_push_tail(q,
"Bob");
g_queue_push_tail(q,
"Fred");
printf(
"First in line is %s\n", g_queue_peek_head(q));
printf(
"Last in line is %s\n", g_queue_peek_tail(q));
printf(
"The queue is %d people long\n", g_queue_get_length(q));
printf(
"%s just bought a ticket\n", g_queue_pop_head(q));
printf(
"Now %s is first in line\n", g_queue_peek_head(q));
printf(
"Someone's cutting to the front of the line\n");
g_queue_push_head(q,
"Big Jim");
printf(
"Now %s is first in line\n", g_queue_peek_head(q));
g_queue_free(q);
return 0;
}

***** Output *****

Is the queue empty?? Yes, adding folks
First in line is Alice
Last in line is Fred
The queue is 3 people long
Alice just bought a ticket
Now Bob is first in line
Someone's cutting to the front of the line
Now Big Jim is first in line

大部分方法名稱都是完全自我描述的,不過(guò)有一些更細(xì)致之處:

* 向隊(duì)列壓入和取出條目的各種操作不返回任何內(nèi)容,所以,為了使用隊(duì)列,您需要保持 g_queue_new 返回的 指針。
* 隊(duì)列的兩端都可以用于添加和刪除。如果要模擬排隊(duì)買票時(shí)排在后面的人離開(kāi)轉(zhuǎn)到另一個(gè)隊(duì)列去購(gòu)買,也是完全可行的。
* 有非破壞性的 peek 操作可以檢查隊(duì)列頭或尾的條目。
* g_queue_free 不接受幫助釋放每個(gè)條目的函數(shù),所以需要手工去完成;這與 GSList 相同。


2
刪除和插入條目

雖然通常只通過(guò)在隊(duì)列的末端 添加/刪除 條目來(lái)修改它,但 GQueue 允許刪除任意條目以及在任意位置插入條目。這里是其示例:

#include <glib.h>
#include
<stdio.h>

int main(int argc, char** argv) {
GQueue
* q = g_queue_new();
g_queue_push_tail(q,
"Alice");
g_queue_push_tail(q,
"Bob");
g_queue_push_tail(q,
"Fred");
printf(
"Queue is Alice, Bob, and Fred; removing Bob\n");
int fred_pos = g_queue_index(q, "Fred");
g_queue_remove(q,
"Bob");
printf(
"Fred moved from %d to %d\n", fred_pos, g_queue_index(q, "Fred"));
printf(
"Bill is cutting in line\n");
GList
* fred_ptr = g_queue_peek_tail_link(q);
g_queue_insert_before(q, fred_ptr,
"Bill");
printf(
"Middle person is now %s\n", g_queue_peek_nth(q, 1));
printf(
"%s is still at the end\n", g_queue_peek_tail(q));
g_queue_free(q);
return 0;
}

***** Output *****

Queue is Alice, Bob, and Fred; removing Bob
Fred moved from 2 to 1
Bill is cutting in line
Middle person is now Bill
Fred is still at the end

有很多新函數(shù):

* g_queue_index 在隊(duì)列中掃描某個(gè)條目并返回其索引;如果它不能找到那個(gè)條目,則返回 -1。
* 為了向隊(duì)列的中間插入一個(gè)新條目,需要一個(gè)指向希望插入位置的指針。如您所見(jiàn),通過(guò)調(diào)用一個(gè)“peek link”函數(shù),

就可以進(jìn)行此處理; 這些函數(shù)包括:g_queue_peek_tail_link、g_queue_peek_head_link 以及 g_queue_peek_nth_link,它們會(huì)返回一個(gè) GList。

然后可以將一個(gè)條目插入到 GList 之前或者之后。

* g_queue_remove 允許從隊(duì)列中的任何位置刪除某個(gè)條目。繼續(xù)使用“排隊(duì)買票”模型,這表示人們可以離開(kāi)隊(duì)列; 他們組成隊(duì)列后并不固定在其中。


3
查找條目

在先前的示例中已經(jīng)看到,在擁有一個(gè)指向條目數(shù)據(jù)的指針或者知道其索引的條件下如何去得到它。

不過(guò),類似其他 GLib 容器, GQueue 也包括一些查找函數(shù):g_queue_find 和 g_queue_find_custom:

#include <glib.h>
#include
<stdio.h>

gint finder(gpointer a, gpointer b) {
return strcmp(a,b);
}
int main(int argc, char** argv) {
GQueue
* q = g_queue_new();
g_queue_push_tail(q,
"Alice");
g_queue_push_tail(q,
"Bob");
g_queue_push_tail(q,
"Fred");
g_queue_push_tail(q,
"Jim");
GList
* fred_link = g_queue_find(q, "Fred");
printf(
"The fred node indeed contains %s\n", fred_link->data);
GList
* joe_link = g_queue_find(q, "Joe");
printf(
"Finding 'Joe' yields a %s link\n", joe_link ? "good" : "null");
GList
* bob = g_queue_find_custom(q, "Bob", (GCompareFunc)finder);
printf(
"Custom finder found %s\n", bob->data);
bob
= g_queue_find_custom(q, "Bob", (GCompareFunc)g_ascii_strcasecmp);
printf(
"g_ascii_strcasecmp also found %s\n", bob->data);
g_queue_free(q);
return 0;
}

***** Output *****

The fred node indeed contains Fred
Finding 'Joe' yields a null link
Custom finder found Bob
g_ascii_strcasecmp also found Bob


注意,如果 g_queue_find 找不到條目,則它會(huì)返回 null。并且可以在上面的示例中傳遞一個(gè)庫(kù)函數(shù)(比如 g_ascii_strcasecmp)

或者一個(gè)定制的函數(shù)(比如 finder)作為 g_queue_find_custom 的 GCompareFunc 參數(shù)。


4
使用隊(duì)列:拷貝、反轉(zhuǎn)和遍歷每一個(gè)(foreach) ?需要調(diào)試

由于 GQueue 的基礎(chǔ)是 GList,所以它支持一些列表處理操作。這里是如何使用 g_queue_copy、 g_queue_reverse 和 g_queue_foreach 的示例:

#include <glib.h>
#include
<stdio.h>

int main(int argc, char** argv) {
GQueue
* q = g_queue_new();
g_queue_push_tail(q,
"Alice ");
g_queue_push_tail(q,
"Bob ");
g_queue_push_tail(q,
"Fred ");
printf(
"Starting out, the queue is: ");
g_queue_foreach(q, (GFunc)printf, NULL);
g_queue_reverse(q);
printf(
"\nAfter reversal, it's: ");
g_queue_foreach(q, (GFunc)printf, NULL);
GQueue
* new_q = g_queue_copy(q);
g_queue_reverse(new_q);
printf(
"\nNewly copied and re-reversed queue is: ");
g_queue_foreach(new_q, (GFunc)printf, NULL);
g_queue_free(q);
g_queue_free(new_q);
return 0;
}

***** Output *****

Starting out, the queue is: Alice Bob Fred
After reversal, it's: Fred Bob Alice
Newly copied and re-reversed queue is: Alice Bob Fred

g_queue_reverse 和 g_queue_foreach 很直觀; 您已經(jīng)看到它們?cè)诟鞣N其他有序集合中得到了應(yīng)用。

不過(guò),使用 g_queue_copy 時(shí)需要稍加留心, 因?yàn)榭截惖氖侵羔樁皇菙?shù)據(jù)。所以,當(dāng)釋放數(shù)據(jù)時(shí),一定不要進(jìn)行重復(fù)釋放。


5
使用鏈接的更多樂(lè)趣

已經(jīng)了解了鏈接的一些示例;這里是一些便利的鏈接刪除函數(shù)。不要忘記 GQueue 中的每個(gè)條目實(shí)際上是都是一個(gè) GList 結(jié)構(gòu)體

, 數(shù)據(jù)存儲(chǔ)在“data”成員中:

#include <glib.h>
#include
<stdio.h>

int main(int argc, char** argv) {
GQueue
* q = g_queue_new();
g_queue_push_tail(q,
"Alice ");
g_queue_push_tail(q,
"Bob ");
g_queue_push_tail(q,
"Fred ");
g_queue_push_tail(q,
"Jim ");
printf(
"Starting out, the queue is: ");
g_queue_foreach(q, (GFunc)printf, NULL);
GList
* fred_link = g_queue_peek_nth_link(q, 2);
printf(
"\nThe link at index 2 contains %s\n", fred_link->data);
g_queue_unlink(q, fred_link);
g_list_free(fred_link);
GList
* jim_link = g_queue_peek_nth_link(q, 2);
printf(
"Now index 2 contains %s\n", jim_link->data);
g_queue_delete_link(q, jim_link);
printf(
"Now the queue is: ");
g_queue_foreach(q, (GFunc)printf, NULL);
g_queue_free(q);
return 0;
}

***** Output *****

Starting out, the queue is: Alice Bob Fred Jim
The link at index 2 contains Fred
Now index 2 contains Jim
Now the queue is: Alice Bob


注意,g_queue_unlink 并不釋放沒(méi)有被鏈接的 GList 結(jié)構(gòu)體,所以需要自己去完成。 并且,由于它是一個(gè) GList 結(jié)構(gòu)體,

所以需要使用 g_list_free 函數(shù)來(lái)釋放它 —— 而不是 簡(jiǎn)單的 g_free 函數(shù)。當(dāng)然,更簡(jiǎn)單的是調(diào)用 g_queue_delete_link 并讓它為您釋放內(nèi)存。


6
排序

隊(duì)列排序好像不太常見(jiàn),不過(guò)由于各種其他鏈表操作都得到了支持(比如 insert 和 remove),所以此操作也得到了支持。

如果恰巧您希望重新對(duì)隊(duì)列進(jìn)行排序,將高優(yōu)先級(jí) 的條目移動(dòng)到前端,那么這也會(huì)很便利。這里是一個(gè)示例:

#include <glib.h>
#include
<stdio.h>

typedef
struct {
char* name;
int priority;
} Task;
Task
* make_task(char* name, int priority) {
Task
* t = g_new(Task, 1);
t
->name = name;
t
->priority = priority;
return t;
}
void prt(gpointer item) {
printf(
"%s ", ((Task*)item)->name);
}
gint sorter(gconstpointer a, gconstpointer b, gpointer data) {
return ((Task*)a)->priority - ((Task*)b)->priority;
}
int main(int argc, char** argv) {
GQueue
* q = g_queue_new();
g_queue_push_tail(q, make_task(
"Reboot server", 2));
g_queue_push_tail(q, make_task(
"Pull cable", 2));
g_queue_push_tail(q, make_task(
"Nethack", 1));
g_queue_push_tail(q, make_task(
"New monitor", 3));
printf(
"Original queue: ");
g_queue_foreach(q, (GFunc)prt, NULL);
g_queue_sort(q, (GCompareDataFunc)sorter, NULL);
printf(
"\nSorted queue: ");
g_queue_foreach(q, (GFunc)prt, NULL);
g_queue_free(q);
return 0;
}

***** Output *****

Original queue: Reboot server?? Pull cable?? Nethack?? New monitor
Sorted queue: Nethack?? Reboot server?? Pull cable?? New monitor

現(xiàn)在您就擁有了一個(gè)模擬您的工作的 GQueue,偶爾還可以對(duì)它進(jìn)行排序,可以欣喜地發(fā)現(xiàn),Nethack 被提升到了其正確的位置,到了隊(duì)列的 最前端!



實(shí)際應(yīng)用

GQueue 沒(méi)有在 Evolution 中得到應(yīng)用,但是 GIMP 和 Gaim 用到了它。

GIMP:

* gimp-2.2.4/app/core/gimpimage-contiguous-region.c 在一個(gè)查找相鄰片段的工具函數(shù)中使用 GQueue 存儲(chǔ)一系列坐標(biāo)。

只要片段保存鄰接,新的點(diǎn)就會(huì)被壓入到隊(duì)列末端,然后在下一個(gè)循環(huán)迭代中取出并被檢查。
* gimp-2.2.4/app/vectors/gimpvectors-import.c 使用 GQueue 作為 Scalable Vector Graphics(SVG)解析器的一部分。

它被當(dāng)做棧使用,條目的壓入和取出都在隊(duì)列的頭上進(jìn)行。

Gaim:

* gaim-1.2.1/src/protocols/msn/switchboard.c 使用 GQueue 來(lái)追蹤發(fā)出的消息。新的消息壓入到隊(duì)列的尾部,當(dāng)發(fā)送后從頭部取出。
* gaim-1.2.1/src/proxy.c 使用 GQueue 追蹤 DNS 查找請(qǐng)求。它使用隊(duì)列作為應(yīng)用程序代碼與 DNS 子進(jìn)程之間的臨時(shí)保存區(qū)域。

總結(jié)

以上是生活随笔為你收集整理的glib 队列的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。