glib 队列

原文地址: 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`

概念

队列是另一个便利的数据结构。一个 队列 会保存一列条目,而且访问形式通常是向最后添加条目,从最前删除条目。

当需要按到达顺序进行处理时,这很有实用。标准队列的一个变种是“双端队列(double-ended queue)”,或者说是 dequeue,

它支持在队列的两端进行添加或者删除。

不过,在很多情况下最好避免使用队列。队列搜索不是特别快(是 O(n) 操作),所以,如果需要经常进行搜索,那么散列表或者树 可能更实用。

这同样适用于需要访问队列中随机元素的情形;如果是那样,那么将会对队列进行很多次线性扫描。

GLib 提供了一个使用 GQueue 的 dequeue 实现;它支持标准队列操作。它的基础是双向链表(GList), 所以它也支持很多其他操作,

比如在队列之中进行插入和删除。不过,如果您发现自己经常要使用这些功能,那么可能需要重新考虑容器的选择; 或许另一个容器更为合适。


1
基本操作

这里是以“排队买票(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

大部分方法名称都是完全自我描述的,不过有一些更细致之处:

* 向队列压入和取出条目的各种操作不返回任何内容,所以,为了使用队列,您需要保持 g_queue_new 返回的 指针。
* 队列的两端都可以用于添加和删除。如果要模拟排队买票时排在后面的人离开转到另一个队列去购买,也是完全可行的。
* 有非破坏性的 peek 操作可以检查队列头或尾的条目。
* g_queue_free 不接受帮助释放每个条目的函数,所以需要手工去完成;这与 GSList 相同。


2
删除和插入条目

虽然通常只通过在队列的末端 添加/删除 条目来修改它,但 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

有很多新函数:

* g_queue_index 在队列中扫描某个条目并返回其索引;如果它不能找到那个条目,则返回 -1。
* 为了向队列的中间插入一个新条目,需要一个指向希望插入位置的指针。如您所见,通过调用一个“peek link”函数,

就可以进行此处理; 这些函数包括:g_queue_peek_tail_link、g_queue_peek_head_link 以及 g_queue_peek_nth_link,它们会返回一个 GList。

然后可以将一个条目插入到 GList 之前或者之后。

* g_queue_remove 允许从队列中的任何位置删除某个条目。继续使用“排队买票”模型,这表示人们可以离开队列; 他们组成队列后并不固定在其中。


3
查找条目

在先前的示例中已经看到,在拥有一个指向条目数据的指针或者知道其索引的条件下如何去得到它。

不过,类似其他 GLib 容器, GQueue 也包括一些查找函数: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 找不到条目,则它会返回 null。并且可以在上面的示例中传递一个库函数(比如 g_ascii_strcasecmp)

或者一个定制的函数(比如 finder)作为 g_queue_find_custom 的 GCompareFunc 参数。


4
使用队列:拷贝、反转和遍历每一个(foreach)  需要调试

由于 GQueue 的基础是 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 很直观; 您已经看到它们在各种其他有序集合中得到了应用。

不过,使用 g_queue_copy 时需要稍加留心, 因为拷贝的是指针而不是数据。所以,当释放数据时,一定不要进行重复释放。


5
使用链接的更多乐趣

已经了解了链接的一些示例;这里是一些便利的链接删除函数。不要忘记 GQueue 中的每个条目实际上是都是一个 GList 结构体

, 数据存储在“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 并不释放没有被链接的 GList 结构体,所以需要自己去完成。 并且,由于它是一个 GList 结构体,

所以需要使用 g_list_free 函数来释放它 —— 而不是 简单的 g_free 函数。当然,更简单的是调用 g_queue_delete_link 并让它为您释放内存。


6
排序

队列排序好像不太常见,不过由于各种其他链表操作都得到了支持(比如 insert 和 remove),所以此操作也得到了支持。

如果恰巧您希望重新对队列进行排序,将高优先级 的条目移动到前端,那么这也会很便利。这里是一个示例:

#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

现在您就拥有了一个模拟您的工作的 GQueue,偶尔还可以对它进行排序,可以欣喜地发现,Nethack 被提升到了其正确的位置,到了队列的 最前端!



实际应用

GQueue 没有在 Evolution 中得到应用,但是 GIMP 和 Gaim 用到了它。

GIMP:

* gimp-2.2.4/app/core/gimpimage-contiguous-region.c 在一个查找相邻片段的工具函数中使用 GQueue 存储一系列坐标。

只要片段保存邻接,新的点就会被压入到队列末端,然后在下一个循环迭代中取出并被检查。
* gimp-2.2.4/app/vectors/gimpvectors-import.c 使用 GQueue 作为 Scalable Vector Graphics(SVG)解析器的一部分。

它被当做栈使用,条目的压入和取出都在队列的头上进行。

Gaim:

* gaim-1.2.1/src/protocols/msn/switchboard.c 使用 GQueue 来追踪发出的消息。新的消息压入到队列的尾部,当发送后从头部取出。
* gaim-1.2.1/src/proxy.c 使用 GQueue 追踪 DNS 查找请求。它使用队列作为应用程序代码与 DNS 子进程之间的临时保存区域。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/548867.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode题库整理【Java】—— 2 两数相加

LeetCode题库整理【Java】 2.两数相加 题目&#xff1a;给出两个 非空 的链表用来表示两个非负的整数。其中&#xff0c;它们各自的位数是按照 逆序 的方式存储的&#xff0c;并且它们的每个节点只能存储 一位 数字。 如果&#xff0c;我们将这两个数相加起来&#xff0c;则会…

用 toto 3分钟建轻量级博客

对于程序员或创业团队来说&#xff0c;还是有必要拥有一个属于自己的博客。Wordpress 曾经让个人或企业搭建博客变得非常容易。但是我们觉得 Wordpress 还是有些重量级&#xff0c;所以选择了一个非常轻便的工具 toto&#xff0c;一段只有200多行代码的Ruby应用程序。 前提条件…

LeetCode题库整理【Java】—— 3 无重复字符的最长子串

LeetCode题库整理【Java】 ## 3 无重复字符的最长子串 题目&#xff1a;给定一个字符串&#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输…

【正式发布】火星人敏捷开发手册2012-12-25(基于Scrum的敏捷开发免费培训教材及公司内部宣传材料)...

2012-12-25&#xff1a;新增松结对编程4页。 预告&#xff1a;下一更新日期&#xff1a;2013-03-01。 您可以在非商业场合免费使用&#xff08;详见文档最后的授权页面&#xff09;&#xff1a; 作为培训前的预习阅读。打印并张贴在公司走廊上。作为企业内部小组培训教材使用。…

Windows下MySQL压缩包.zip的安装

安装教程可参考这篇文章&#xff1a; Windows下通过压缩包zip形式安装mysql数据库 重点是在安装过程中可能遇到的问题&#xff1a; 除了MYSQL服务无法启动&#xff0c;服务没有任何错误&#xff1b;解决方法这里提到的问题&#xff0c; 我遇到的问题是 unknown variable ‘de…

10g中如何修改数据库字符集-2

从上面的安装结果输出信息来看&#xff0c;下面的2条授权语句执行失败了&#xff0c; grant READ on directory log_file_dir to system grant READ on directory data_file_dir to system 这两句授权的语句&#xff0c;是没什么用的&#xff0c;完全可以从scminst.sql脚本中删…

SpringMVC学习笔记-新建工程及一些注意事项

1、学习网站 &#xff1a;B站狂神说 狂神说的文档链接&#xff1a;https://mp.weixin.qq.com/s/8ddT6FD0Y4f3XdbEz0aqpQ 2、新建SpringMVC工程 &#xff08;我的是IDEA2020.3&#xff09; &#xff08;1&#xff09;新建工程 &#xff08;2&#xff09;命名 &#xff08;3&a…

HPC存储三种方案

我们常说工匠做合适的工作需要选择正确的工具。虽然这句话随处可见&#xff0c;但它却道出了设计和制造HPC系统的精髓。一直以来&#xff0c;HPC的计算部分都是用这种方法选择处理器和内存并设计互联结构、规定软件栈和工具。当然&#xff0c;这一切都和存储密不可分。   要实…

SpringMVC之——转发与重定向

与视图解析器的关系 有视图解析器时转发和重定向都可以成功&#xff0c; 无视图解析器时转发需要补全路径才能成功&#xff0c;重定向不能访问WEB-INF下的页面&#xff08;如图中的test.jsp&#xff09; 视图解析器配置在web.xml中绑定的springmvc配置文件中 有视图解析器时 转…

生活有点乱

最近的生活有点乱&#xff0c;每天家里总是很乱&#xff0c;真恨不得把锅碗都砸了&#xff0c;今天需迅速的把打印做完&#xff0c;然后这个软件就放下了&#xff0c;开始研究多线程和socket&#xff0c;工作必须每天都能学到新东西&#xff0c;学习必须每天都要进步&#xff0…

什么是JSON? 以及jackson的使用

1、题外话 前后端分离时代 后端部署后端&#xff0c;提供接口&#xff0c;提供数据 json 前端独立部署&#xff0c;负责渲染后端的数据 2、什么是JSON JSON(JavaScript Object Notation, JS对象标记)是一种轻量级的数据交换格式&#xff0c;目前使用特别广泛。 ●采用完全独立…

fastjson

1、在pom.xml中导入依赖 <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.60</version></dependency>2、fastjson三个主要的类: ●[JSONObject代表json对象] JSONObject实现了Map…

流程图

开始和结束可以使用椭圆形&#xff0c;条件判断可以用菱形&#xff0c;一般的处理用矩形&#xff0c;使用带箭头的线把程序的执行流程标出来就行了 最要的是表示出系统每一步都做什么转载于:https://www.cnblogs.com/mmnyjq/archive/2011/07/20/2112002.html

新建Mybatis工程

1、新建一个普通的Maven工程&#xff0c;点击next 在需要的目录下命名你的工程&#xff0c;点击finish 2、在pom.xml中导入依赖&#xff0c;包含mysql,mybatis和单元测试三个部分的依赖 <?xml version"1.0" encoding"UTF-8"?> <project xml…

win2003服务器 虚拟主机安全配置

win2003服务器 虚拟主机安全配置注入漏洞、上传漏洞、弱口令漏洞等问题随处可见。跨站***&#xff0c;远程控制等等是再老套不过了的话题。有些虚拟主机管理员不知是为了方便还是不熟悉配置&#xff0c;干脆就将所有的网站都放在同一个目录中&#xff0c;然后将上级目录设置为站…

org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the

错误&#xff1a;绑定异常 org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry.at org.apache.ibatis.binding.MapperRegistry.getMapper(MapperRegistry.java:47)at org.apache.ibatis.session.Configur…

一个H3CNE测试的配置

H3CNE的配置 拓扑图&#xff1a; R1[R1]dis cu#version 5.20, Alpha 1011#sysname R1#password-control login-attempt 3 exceed lock-time 120#undo voice vlan mac-address 00e0-bb00-0000#ipsec cpu-backup enable#undo cryptoengine enable#nat address-group 0 10.1.1.3 1…

Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration.

错误&#xff1a;找不到Mapper.xml org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession. ### The error may exist in com/kuang/UserMapper.xml ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configu…

推荐5个应用 jQuery 特效的精美网站

jQuery 在现在的 Web 开发项目中扮演着重要角色&#xff0c;借助 jQuery 可以让网站有更好的可用性和用户体验&#xff0c;让访问者对网站留下非常好的印象。今天这篇文章向大家分享5个应用 jQuery 的精美网站&#xff0c;一起欣赏。 Webalon 非常好的图片滑动效果&#xff0c;…

mybatis进行CRUD操作时返回值不为影响的条数,为null

对应自己的情况多试试看&#xff0c;总有一种方法可以解决吧&#xff01; 1、如果报期望的返回值为null而原始返回值类型为int的错误 则将Dao/mapper接口中的函数的返回值类型改为Integer&#xff0c;在方法调用时使用.intValue()方法转换为int就可以了。 2、配置返回为修改…