Glib学习(3) 双端队列 Double-ended Queues

在数据结构中两种重要的类型就是队列和栈,而什么又是双端队列呢?

双端队列是一个限定插入和删除操作的数据结构,具有队列和的性质。

(deque,全名double-ended queue)是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。

也就是说双端队列是队列和栈的集合,通过规则来灵活的实现队列和栈的功能。


下面还是先贴出来GLib Reference Manual网址

http://web.mit.edu/barnowl/share/gtk-doc/html/glib/glib-Double-ended-Queues.html#g-queue-copy


GQueue结构体及其相关函数提供了一个标准的队列数据结构。在内部,GQueue使用和glist相同的数据结构来存储元素。可以存储一个int型的数据,或者使用类型转换宏 Type Conversion Macros,去转换成任何数据类型的指针。

创建一个队列使用g_queue_new()

初始化一个静态的队列使用G_QUEUE_INIT 或者 g_queue_init()


这里就涉及到new和init的区别了,在操作系统中,通过动态申请内存,分配在堆上的使用new实现,分配在栈上的使用init实现。在编程的区别就是new的方法可以在程序中动态实现,init在编译之前就已经知道在哪里了。


添加元素使用 g_queue_push_head()g_queue_push_head_link()g_queue_push_tail() 和 g_queue_push_tail_link()

删除元素使用  g_queue_pop_head() 和 g_queue_pop_tail()

释放全部队列使用  g_queue_free()


下面看一下结构体

GQueue

typedef struct {
  GList *head;
  GList *tail;
  guint  length;
} GQueue;

head指向队列的第一个元素

tail指向队列的最后一个元素

length是队列的元素个数


下面是队列提供的函数


Synopsis

#include <glib.h>


                    GQueue;
GQueue*             g_queue_new                         (void);
void                g_queue_free                        (GQueue *queue);
#define             G_QUEUE_INIT
void                g_queue_init                        (GQueue *queue);
void                g_queue_clear                       (GQueue *queue);
gboolean            g_queue_is_empty                    (GQueue *queue);
guint               g_queue_get_length                  (GQueue *queue);
void                g_queue_reverse                     (GQueue *queue);
GQueue*             g_queue_copy                        (GQueue *queue);
void                g_queue_foreach                     (GQueue *queue,
                                                         GFunc func,
                                                         gpointer user_data);
GList*              g_queue_find                        (GQueue *queue,
                                                         gconstpointer data);
GList*              g_queue_find_custom                 (GQueue *queue,
                                                         gconstpointer data,
                                                         GCompareFunc func);
void                g_queue_sort                        (GQueue *queue,
                                                         GCompareDataFunc compare_func,
                                                         gpointer user_data);
void                g_queue_push_head                   (GQueue *queue,
                                                         gpointer data);
void                g_queue_push_tail                   (GQueue *queue,
                                                         gpointer data);
void                g_queue_push_nth                    (GQueue *queue,
                                                         gpointer data,
                                                         gint n);
gpointer            g_queue_pop_head                    (GQueue *queue);
gpointer            g_queue_pop_tail                    (GQueue *queue);
gpointer            g_queue_pop_nth                     (GQueue *queue,
                                                         guint n);
gpointer            g_queue_peek_head                   (GQueue *queue);
gpointer            g_queue_peek_tail                   (GQueue *queue);
gpointer            g_queue_peek_nth                    (GQueue *queue,
                                                         guint n);
gint                g_queue_index                       (GQueue *queue,
                                                         gconstpointer data);
void                g_queue_remove                      (GQueue *queue,
                                                         gconstpointer data);
void                g_queue_remove_all                  (GQueue *queue,
                                                         gconstpointer data);
void                g_queue_insert_before               (GQueue *queue,
                                                         GList *sibling,
                                                         gpointer data);
void                g_queue_insert_after                (GQueue *queue,
                                                         GList *sibling,
                                                         gpointer data);
void                g_queue_insert_sorted               (GQueue *queue,
                                                         gpointer data,
                                                         GCompareDataFunc func,
                                                         gpointer user_data);
void                g_queue_push_head_link              (GQueue *queue,
                                                         GList *link_);
void                g_queue_push_tail_link              (GQueue *queue,
                                                         GList *link_);
void                g_queue_push_nth_link               (GQueue *queue,
                                                         gint n,
                                                         GList *link_);
GList*              g_queue_pop_head_link               (GQueue *queue);
GList*              g_queue_pop_tail_link               (GQueue *queue);
GList*              g_queue_pop_nth_link                (GQueue *queue,
                                                         guint n);
GList*              g_queue_peek_head_link              (GQueue *queue);
GList*              g_queue_peek_tail_link              (GQueue *queue);
GList*              g_queue_peek_nth_link               (GQueue *queue,
                                                         guint n);
gint                g_queue_link_index                  (GQueue *queue,
                                                         GList *link_);
void                g_queue_unlink                      (GQueue *queue,
                                                         GList *link_);
void                g_queue_delete_link                 (GQueue *queue,
                                                         GList *link_);

下面提供一段测试代码,


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

struct map {
    int key;
    char *value;
} m[10] = {
    {0,"zero"},
    {1,"one"},
    {2,"two"},
    {3,"three"},
    {4,"four"},
    {5,"five"},
    {6,"six"},
    {7,"seven"},
    {8,"eight"},
    {9,"nine"},
};
typedef struct map map;

static void
myPrintInt(gpointer p1, gpointer fmt)
{
    g_printf(fmt, *(gint *)p1);
}

static void
myPrintStr(gpointer p1, gpointer fmt)
{
    g_printf(fmt, (gchar *)p1);
}

static void
test_queue_1(void)
{
// GQueue* g_queue_new(void);   创建队列
    GQueue *queue = g_queue_new();
// gboolean g_queue_is_empty(GQueue *queue);    判断队列是否为空,空返回1
    gboolean b = g_queue_is_empty(queue);
    g_printf("The queue should be empty now.\t\tResult: %s.\n", b ? "YES" : "NO");

// void g_queue_push_tail(GQueue *queue, gpointer data);    将数据data压入队列尾部
    gint i;
    for (i = 0; i < sizeof (m) / sizeof (m[0]); i++)
        g_queue_push_tail(queue, m[i].value);
    
// void g_queue_foreach(GQueue *queue, GFunc func, gpointer user_data);     调用函数func遍历队列元素,user_data是函数的参数
    g_printf("Now the queue[after push tail] :\n");
    g_queue_foreach(queue, myPrintStr, "%s, ");//打印字符串的形式输出队列的数据,因为之前是将map中的value,即字符串数据保存到了队列中
    g_printf("\n");

// guint g_queue_get_length(GQueue *queue);     得到队列元素的个数
    g_printf("The lenght should be '%d' now.\t\tResult: %d.\n", 10, g_queue_get_length(queue));

// void g_queue_reverse(GQueue *queue);     翻转队列的元素
    g_queue_reverse(queue);
    g_printf("Now the queue[after reverse] :\n");
    g_queue_foreach(queue, myPrintStr, "%s, ");
    g_printf("\n");

// gpointer g_queue_pop_head(GQueue *queue);    从头部取出一个数据
    g_printf("The head should be '%s' now.\t\tResult: %s.\n", "nine", (gchar *)g_queue_pop_head(queue));

// gpointer g_queue_pop_tail(GQueue *queue);    从尾部取出一个数据
    g_printf("The tail should be '%s' now.\t\tResult: %s.\n", "zero", (gchar *)g_queue_pop_tail(queue));
    g_printf("Now the queue[after pop head and tail] :\n");
    g_queue_foreach(queue, myPrintStr, "%s, ");
    g_printf("\n");

// gpointer g_queue_pop_nth(GQueue *queue, guint n);    将第n个数据取出
    g_printf("The head should be '%s' now.\t\tResult: %s.\n", "eight", (gchar *)g_queue_pop_nth(queue, 0));

// void g_queue_push_head(GQueue *queue, gpointer data);    将数据data压入队列头
    g_queue_push_head(queue, "zero");
    g_queue_push_head(queue, "eight");

// void g_queue_push_nth(GQueue *queue, gpointer data, gint n);     将data插入第n个位置
    g_queue_push_nth(queue, "nine", 2);

    g_printf("Now the queue[after push 'zero' 'eight' 'nine'] :\n");
    g_queue_foreach(queue, myPrintStr, "%s, ");
    g_printf("\n");

// gpointer g_queue_peek_head(GQueue *queue);       查看头数据,不取出
    g_printf("The head should be '%s' now.\t\tResult: %s.\n", "eight", (gchar *)g_queue_peek_head(queue));

// gpointer g_queue_peek_tail(GQueue *queue);       查看尾数据,不取出
    g_printf("The tail should be '%s' now.\t\tResult: %s.\n", "one", (gchar *)g_queue_peek_tail(queue));

// gpointer g_queue_peek_nth(GQueue *queue, guint n);   查看第n个数据,不取出
    g_printf("The head should be '%s' now.\t\tResult: %s.\n", "eight", (gchar *)g_queue_peek_nth(queue, 0));

/*
// void g_queue_clear(GQueue *queue);   清理队列,如果数据是动态申请的, 在调用这个函数之前需要先释放数据,这个函数是与init配套使用的,new配套使用free
    g_queue_clear(queue);
    g_printf("Now the queue[after clear] :\n");
    g_queue_foreach(queue, myPrintStr, "%s, ");
    g_printf("\n");
*/

// void g_queue_free(GQueue *queue);    释放队列
    g_queue_free(queue);
}

static gint
sort(gconstpointer p1, gconstpointer p2, gpointer user_data)//正向排序规则
{
    gint32 a, b;
    
    a = *(gint*)(p1);
    b = *(gint*)(p2);

    return (a > b ? +1 : a == b ? 0 : -1);
}

static gint
myCompareInt(gconstpointer p1, gconstpointer p2)//比较大小
{
    const int *a = p1;
    const int *b = p2;

    return *a - *b;
}


static gint
sort_r(gconstpointer p1, gconstpointer p2, gpointer user_data)//逆向排序规则
{
    gint32 a, b;
    
    a = *(gint*)(p1);
    b = *(gint*)(p2);

    return (a < b ? +1 : a == b ? 0 : -1);
}

static void
test_queue_2(void)
{
    GQueue *queue = NULL;
/*
// void g_queue_init(GQueue *queue);    在栈中申请队列
    g_queue_init(queue);
*/
    queue = g_queue_new();

// void g_queue_insert_sorted(GQueue *queue, gpointer data, GCompareDataFunc func gpointer user_data);  按照func规则进行插入队列
    gint i;
    for (i = 0; i < sizeof (m) / sizeof (m[0]); i++)
        g_queue_insert_sorted(queue, &m[i].key, sort_r, NULL);

    g_printf("Now the queue[after insert sorted] :\n");
    for (i = 0; i < queue->length; i++)
        g_printf("%d, ", *(gint *)g_queue_peek_nth(queue, i));
    g_printf("\n");

// void g_queue_remove(GQueue *queue, gconstpointer data);      将队列中的data数据移除,只移除第一次出现的数据
    g_queue_remove(queue, &m[3].key);
    g_printf("Now the queue[after remove '%d'] :\n", m[3].key);
    for (i = 0; i < queue->length; i++)
        g_printf("%d, ", *(gint *)g_queue_peek_nth(queue, i));
    g_printf("\n");

// GList* g_queue_find_custom(GQueue *queue, gconstpointer data, GCompareFunc func);    通过比较函数func查找数据data
// void g_queue_insert_before(GQueue *queue, GList *sibling, gpointer data);            将数据data插入到sibling前面
// void g_queue_insert_after(GQueue *queue, GList *sibling, gpointer data);             将数据data插入到sibling后面
    g_queue_insert_before(queue, g_queue_find_custom(queue, &m[5].key, myCompareInt), &m[3].key);
    g_queue_insert_after(queue, g_queue_find_custom(queue, &m[5].key, myCompareInt), &m[3].key);

    g_printf("Now the queue[after insert '%d' around '%d'] :\n", m[3].key, m[5].key);
    g_queue_foreach(queue, myPrintInt, "%d, ");
    g_printf("\n");

// void g_queue_sort(GQueue *queue, GCompareDataFunc compare, gpointer user_data);  通过比较函数compare进行排序
    g_queue_sort(queue, sort, NULL);

    g_printf("Now the queue[sorted] :\n");
    g_queue_foreach(queue, myPrintInt, "%d, ");
    g_printf("\n");

// GQueue* g_queue_copy(GQueue *queue);     复制队列,同样,也只是指针的复制,并没有实际复制数据
    GQueue *q = g_queue_copy(queue);
    g_printf("Now the queue[copy] :\n");
    g_queue_foreach(q, myPrintInt, "%d, ");
    g_printf("\n");

// void g_queue_remove_all(GQueue *queue, gconstpointer data);      删除队列中所有的data数据
    g_queue_remove_all(q, &m[3].key);
    g_printf("Now the queue[remove '%d'] :\n", m[3].key);
    g_queue_foreach(q, myPrintInt, "%d, ");
    g_printf("\n");

    g_queue_free(q);
    g_queue_free(queue);
}

int
main(void)
{
    printf("BEGIN:\n************************************************************\n");
    printf("\n------------------------------------------------------------\ntest_queue_1:\n");
    test_queue_1();
    printf("------------------------------------------------------------\n");
    printf("\n------------------------------------------------------------\ntest_queue_2:\n");
    test_queue_2();
    printf("------------------------------------------------------------\n");
    printf("\n************************************************************\nDONE\n");

    return 0;
}


运行结果:


linux@ubuntu:~/16021/glibdemo$ gcc -o Double_ended_Queues Double_ended_Queues.c -lglib-2.0
Double_ended_Queues.c: In function ‘test_queue_2’:
Double_ended_Queues.c:183:17: warning: initialization makes pointer from integer without a cast [enabled by default]
linux@ubuntu:~/16021/glibdemo$ ./Double_ended_Queues 
BEGIN:
************************************************************

------------------------------------------------------------
test_queue_1:
The queue should be empty now.		Result: YES.
Now the queue[after push tail] :
zero, one, two, three, four, five, six, seven, eight, nine, 
The lenght should be '10' now.		Result: 10.
Now the queue[after reverse] :
nine, eight, seven, six, five, four, three, two, one, zero, 
The head should be 'nine' now.		Result: nine.
The tail should be 'zero' now.		Result: zero.
Now the queue[after pop head and tail] :
eight, seven, six, five, four, three, two, one, 
The head should be 'eight' now.		Result: eight.
Now the queue[after push 'zero' 'eight' 'nine'] :
eight, zero, nine, seven, six, five, four, three, two, one, 
The head should be 'eight' now.		Result: eight.
The tail should be 'one' now.		Result: one.
The head should be 'eight' now.		Result: eight.
------------------------------------------------------------

------------------------------------------------------------
test_queue_2:
Now the queue[after insert sorted] :
9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 
Now the queue[after remove '3'] :
9, 8, 7, 6, 5, 4, 2, 1, 0, 
Now the queue[after insert '3' around '5'] :
9, 8, 7, 6, 3, 5, 3, 4, 2, 1, 0, 
Now the queue[sorted] :
0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 
Now the queue[copy] :
0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 
Now the queue[remove '3'] :
0, 1, 2, 4, 5, 6, 7, 8, 9, 
------------------------------------------------------------

************************************************************
DONE
linux@ubuntu:~/16021/glibdemo$ 


好了,常用的函数基本就这些,明天按照顺序应该是序列,但是序列往往用在数据库的主键上,而每个数据库有没有统一的规则,所以应用并不多,暂时先不进行研究,顺序进行hash的研究。


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值