Glib库常用数据结构.docx
- 文档编号:9312336
- 上传时间:2023-05-18
- 格式:DOCX
- 页数:66
- 大小:43.25KB
Glib库常用数据结构.docx
《Glib库常用数据结构.docx》由会员分享,可在线阅读,更多相关《Glib库常用数据结构.docx(66页珍藏版)》请在冰点文库上搜索。
Glib库常用数据结构
Glib常用数据结构
(1)
2010-01-0518:
59
intmain(intargc,char**argv){
GSList*list=NULL;
list=g_slist_append(list,"second");
list=g_slist_prepend(list,"first");
g_printf("Thelistisnow%ditemslong\n",g_slist_length(list));
list=g_slist_remove(list,"first");
g_g_printf("Thelistisnow%ditemslong\n",g_slist_length(list));
g_slist_free(list);
return0;
}
*****Output*****
Thelistisnow2itemslong
Thelistisnow1itemslong
这段代码中大部分看起来都比较熟悉,不过有一些地方需要考虑;
*如果调用g_slist_remove时传递了一个并不在列表中的条目,那么列表将不会发生变化。
*g_slist_remove也会返回列表的新起始位置。
*可以发现,“first”是调用g_slist_prepend添加的。
这是个调用比g_slist_append更快;它是O
(1)操作而不是O(n)操作,原因如前所述,进行附加需要遍历整个列表。
所以,如果使用g_slist_prepend更为方便,那么就应该使用它。
删除重复的条目
这里是当在一个列表中有重复的条目时会发生的问题:
//ex-gslist-3.c
#include
intmain(intargc,char**argv){
GSList*list=NULL;
list=g_slist_append(list,"first");
list=g_slist_append(list,"second");
list=g_slist_append(list,"second");
list=g_slist_append(list,"third");
list=g_slist_append(list,"third");
g_printf("Thelistisnow%ditemslong\n",g_slist_length(list));
list=g_slist_remove(list,"second");
list=g_slist_remove_all(list,"third");
g_printf("Thelistisnow%ditemslong\n",g_slist_length(list));
g_slist_free(list);
return0;
}
*****Output*****
Thelistisnow5itemslong
Thelistisnow2itemslong
所以,如果GSList包含了两个同样的指针,而调用了g_slist_remove,那么只会删除第一个指针。
不过,可以使用g_slist_remove_all删除条目的所有指针。
最后一个、第n个和第n个数据
在GSList中有了一些条目后,可以通过不同的方式提取它们。
这里是一些示例,并在g_printf语句中给出了解释。
//ex-gslist-4.c
#include
intmain(intargc,char**argv){
GSList*list=NULL;
list=g_slist_append(list,"first");
list=g_slist_append(list,"second");
list=g_slist_append(list,"third");
g_printf("Thelastitemis'%s'\n",g_slist_last(list)->data);
g_printf("Theitematindex'1'is'%s'\n",g_slist_nth(list,1)->data);
g_printf("Nowtheitematindex'1'theeasyway:
'%s'\n",g_slist_nth_data(list,1));
g_printf("Andthe'next'itemafterfirstitemis'%s'\n",g_slist_next(list)->data);
g_slist_free(list);
return0;
}
*****Output*****
Thelastitemis'third'
Theitematindex'1'is'second'
Nowtheitematindex'1'theeasyway:
'second'
Andthe'next'itemafterfirstitemis'second'
注意,有一些可以作用于GSList的快捷函数;可以简单地调用g_slist_nth_data,而不需调用先g_slist_nth然后再反引用(dereference)返回的指针。
最后一个g_printf语句稍有不同。
g_slist_next不是一个函数调用,而是一个宏。
它展开为一个指向GSList中下一元素的指针反引用。
在这种情况下,可以看到,我们传递了GSList中的第一个元素,于是那个宏展并给出第二个元素。
这也是一个快速的操作,因为没有函数调用的开销。
退一步:
使用用户定义的类型---结构体
到现在为止我们一直在使用字符串;也就是说,我们只是将指向字符的指针放入到GSList中。
在下面的代码示例中,将会定义一个Person结构体,并将这个结构体的一些实例放入到GSList中:
//ex-gslist-5.c
#include
#include
typedefstruct{
char*name;
intshoe_size;
}Person;
intmain(intargc,char**argv){
GSList*list=NULL;
Person*tom=(Person*)malloc(sizeof(Person));
tom->name="Tom";
tom->shoe_size=12;
list=g_slist_append(list,tom);
Person*fred=g_new(Person,1);//allocatememoryforonePersonstruct
fred->name="Fred";
fred->shoe_size=11;
list=g_slist_append(list,fred);
g_printf("Tom'sshoesizeis'%d'\n",((Person*)list->data)->shoe_size);
g_printf("ThelastPerson'snameis'%s'\n",((Person*)g_slist_last(list)->data)->name);
g_slist_free(list);
free(tom);
g_free(fred);
return0;
}
*****Output*****
Tom'sshoesizeis'12'
ThelastPerson'snameis'Fred'
关于使用GLib和用户定义类型的一些注解:
*可以像使用字符串一样在GSList使用用户定义类型。
另外要注意,当从列表中取出条目时,需要进行一些强制类型转换。
*这个示例使用了另一个GLib宏——g_new宏——来创建FredPerson实例。
这个宏只是展开并使用malloc为给定的类型分配适当数量的内存,但是这比手工输入malloc函数调用更为简洁。
*最后,如果要分配内存,那么还需要释放它。
可以看到上面的代码示例如何使用GLib函数g_free来为FredPerson实例完成此任务(因为它是使用g_new分配的)。
在大部分情况下g_free只是会包装free函数,但是GLib也具备内存池功能,g_free以及其他内存管理函数可以使用它们。
组合、反转,等等
GSList附带了一些便利的工具,可以连接和反转列表。
这里是它们的工作方式:
//ex-gslist-6.c
#include
voiddisplay_list(GSList*list)
{
GSList*iterator=NULL;
for(iterator=list;iterator;iterator=iterator->next)
{
g_printf("%s",(int*)iterator->data);
}
g_printf("\n");
}
intmain(intargc,char**argv)
{
GSList*list1=NULL;
list1=g_slist_append(list1,"first");
list1=g_slist_append(list1,"second");
GSList*list2=NULL;
list2=g_slist_append(list2,"third");
list2=g_slist_append(list2,"fourth");
GSList*both=g_slist_concat(list1,list2); //连接两个表
display_list(both);
g_printf("Thethirditemintheconcatenatedlistis'%s'\n",g_slist_nth_data(both,2));
GSList*reversed=g_slist_reverse(both); //反转一个表
g_printf("Thefirstiteminthereversedlistis'%s'\n",reversed->data);
display_list(reversed);
g_slist_free(reversed);
return0;
}
OUT:
:
:
firstsecondthirdfourth
Thethirditemintheconcatenatedlistis'third'
Thefirstiteminthereversedlistis'fourth'
fourththirdsecondfirst
正如所预期的,两个列表首尾相连在一起,list2中的第一个条目成为新的列表中的第三个条目。
注意,并没有拷贝条目;它们只是被链接上,这样内存只需要释放一次。
另外,您会发现您只需要使用一个指针反引用(reversed->data)就可以打印出反向列表的第一个条目。
由于GSList中的每一个条目都是一个指向某个GSList结构体的指针,所以要获得第一个条目并不需要调用函数。
简单遍历
这里是遍历GSList中所有内容的一个直观方法:
//ex-gslist-7.c
#include
intmain(intargc,char**argv){
GSList*list=NULL,*iterator=NULL;
list=g_slist_append(list,"first");
list=g_slist_append(list,"second");
list=g_slist_append(list,"third");
for(iterator=list;iterator;iterator=iterator->next){
g_printf("Currentitemis'%s'\n",iterator->data);
}
g_slist_free(list);
return0;
}
*****Output*****
Currentitemis'first'
Currentitemis'second'
Currentitemis'third'
迭代器(iterator)对象只是一个声明为指向GSList结构体的变量。
这看似奇怪,不过却能满足要求。
由于单向列表是一系列GSList结构体,所以迭代器与列表的类型应该相同。
另外,注意这个代码段使用的是通常的GLib用法习惯;在声明GSList本身的时候就声明了迭代器变量。
最后,for循环的退出表达式检查迭代器是否为NULL。
这样是有效的,因为只有当循环传递了列表中的最后一个条目后它才会成为NULL。
使用函数进行高级遍历
遍历列表的另一种方法是使用g_slist_foreach,并提供一个将为列表中的每一个条目调用的函数。
//ex-gslist-8.c
#include
voidprint_iterator(gpointeritem,gpointerprefix)
{
g_printf("%s%s\n",prefix,item);
}
voidprint_iterator_short(gpointeritem)
{
g_printf("%s\n",item);
}
intmain(intargc,char**argv)
{
GSList*list=g_slist_append(NULL,g_strdup("1"));
list=g_slist_append(list,g_strdup("2"));
list=g_slist_append(list,g_strdup("third"));
g_printf("Iteratingwithafunction:
\n");
g_slist_foreach(list,print_iterator,"-->"); 如果第一个条目小于第二个,则GCompareFunc返回一个负值,如果相等则返回0,如果第二个大于第一个则返回一个正值 //链表中的每个元素都调用上面的子函数 同时在每个输出前加“-->”
g_printf("Iteratingwithashorterfunction:
\n");
g_slist_foreach(list,(GFunc)print_iterator_short,NULL);
g_printf("Nowfreeingeachitem\n");
g_slist_free(list);
return0;
}
*****Output*****
Iteratingwithafunction:
-->first
-->second
-->third
Iteratingwithashorterfunction:
first
second
third
Nowfreeingeachitem
注意:
g_slist_foreach(list,print_iterator,"-->"); 中第一个参数是链表
第二个参数是调用的上面的子函数
第三个函数是子函数中第二个参数
在这个示例中有很多好东西:
*一条类似GSListx=g_slist_append(NULL,[whatever])的语句让您能够一举声明、初始化并将第一个条目添加到列表。
*g_strdup函数可以方便地复制字符串;如果使用了它,那么要记得释放。
*g_slist_foreach允许传递一个指针,这样就可以根据列表中的每个条目有效地为其赋与任意参数。
例如,可以传递一个累加器并收集关于列表中每个条目的信息。
遍历函数的唯一受限之处在于它至少要使用一个gpointer作为参数;现在可以了解在只接收一个参数时print_interator_short如何工作。
*注意,代码使用一个内置的GLib函数作为g_slist_foreach的参数来释放所有字符串。
在此示例中,所有需要做的只是将g_free强制类型转换为GFunc以使其生效。
注意,仍然可以单独使用g_slist_free来释放GSList本身。
使用GCompareFunc排序
可以通过提供一个知道如何比较列表中条目的函数来对GSLit进行排序。
下面的示例展示了对字符串列表进行排序的一种方法:
((((((((((未仔细看)))))))))
//ex-gslist-9.c
#include
gintmy_comparator(gconstpointeritem1,gconstpointeritem2)
{
returng_ascii_strcasecmp(item1,item2); ////比较两个条目,如果第一个条目小于第二个,则返回一个负值,如果相等则返回0,如果第二个大于第 一个则返回一个正值
}
intmain(intargc,char**argv){
GSList*list=g_slist_append(NULL,"Chicago");
list=g_slist_append(list,"Boston");
list=g_slist_append(list,"Albany");
list=g_slist_sort(list,(GCompareFunc)my_comparator); ///按从小到大到数据进行排列
g_printf("Thefirstitemisnow'%s'\n",list->data);
g_printf("Thelastitemisnow'%s'\n",g_slist_last(list)->data);
g_slist_free(list);
return0;
}
*****Output*****
Thefirstitemisnow'Albany'
Thelastitemisnow'Chicago'
注意,如果第一个条目小于第二个,则GCompareFunc返回一个负值,如果相等则返回0,如果第二个大于第一个则返回一个正值。
只要您的比较函数符合此规范,在内部它可以做任何所需要的事情。
另外,由于各种其他GLib函数也遵循此模式,所以可以简单地委派给它们。
实际上,在上面的示例中,可以简单地把my_comparator调用替换为g_slist_sort(list,(GCompareFunc)g_ascii_strcasecmp)等调用,会获得相同的结果。
查找元素
有一些方法可以在GSList查找元素。
已经介绍了如何简单地遍历列表的全部内容,比较每个条目,直到找到了目标条目。
如果已经拥有了要寻找的数据,而只是想要获得它在列表中的位置,那么可以使用g_slist_find。
最后,可以使用g_slist_find_custom,它允许您使用一个函数来检查列表中的每一个条目。
下面展示了g_slist_find和g_slist_find_custom:
//ex-gslist-10.c
#include
gintmy_finder(gconstpointeritem){
returng_ascii_strcasecmp(item,"second");
}
intmain(intargc,char**argv){
GSList*list=g_slist_append(NULL,"first");
list=g_slist_append(list,"second");
list=g_slist_append(list,"third");
GSList*item=g_slist_find(list,"second");
g_printf("Thisshouldbethe'second'item:
'%s'\n",item->data);
item=g_slist_find_custom(list,NULL,(GCompareFunc)my_finder);
g_printf("Again,thisshouldbethe'second'item:
'%s'\n",item->data);
item=g_slist_find(list,"delta");
g_printf("'delta'isnotinthelist,soweget:
'%s'\n",item?
item->data:
"(null)");
g_slist_free(list);
return0;
}
*****Output*****
Thisshouldbethe'second'item:
'second'
Again,thisshouldbethe'second'item:
'second'
'delta'isnotinthelist,soweget:
'(null)'
注意,g_slist_find_custom也使用了一个可以指向任意内容的指针作为第二个参数,所以,如果需要,可以传递进来一些内容以帮助查找函数。
另外,GCompare函数是最后一个参数,而不是第二个参数,因为它在g_slist_sort之中。
最后,失败的查找会返回NULL。
通过插入进行高级添加
既然已经接触过几次GCompareFunc,一些更有趣的插入操
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Glib 常用 数据结构