查看原文
其他

队列,C语言实现

The following article is from 嵌入式Linux Author 写代码的篮球球痴

什么是队列?

上一篇文章写了什么是栈,用C语言实现了栈,既然说了栈,不说队列,感觉总是少了点什么,所以就顺手写一个队列,而且最近做项目也用到这个队列的代码。

栈的特点是先进后出,队列的特点是先进先出,从这个特点可以知道,队列是比较友好的,不像栈那样最开始进去排队的人,竟然是最后一个出来的。

新建一个队列

因为我这个例程是使用链表实现队列的,所以新建一个队列,实际上就是开辟一个内存空间,用来存储队列的头部。跟栈一样,我们理解了建立一个队列就是需要建立一个头,开辟的这个空间,代表的是这个队列,就好比,你老爸就可以代表你们家庭,不管你家有多少人,有多少个小孩,你老爸始终都是这个家庭的户主。

/*创建队列,外部释放内存*/QueueInfo_st *createQueue(void){ QueueInfo_st *queue = (QueueInfo_st *)malloc(sizeof(QueueInfo_st)); if(NULL == queue) { printf("malloc failed\n"); return NULL; } queue->next = NULL; return queue;}

向队列中插入数据

向队列插入数据,我做的有点麻烦,先是遍历链表,找到这个链表的尾部,然后再在链表的尾部插入数据,看文章的大神,有好的方法可以指出来,我觉得应该有更加优秀的方法的。

/*入队列,0表示成,非0表示出错*/int queue_push(QueueInfo_st *s,ElementType value){ /*用来保存尾部指针*/ QueueInfo_st *temp = (QueueInfo_st *)malloc(sizeof(QueueInfo_st)); if(NULL == temp) { printf("malloc failed\n"); return FAILURE; }
/*找到链表的尾部*/ while(s->next != NULL) { s = s->next; }
temp->value = value; temp->next = s->next; s->next = temp;
return SUCCESS;}

取出队列的数据

取出队列的数据,也就是把头部指向的下一个链表里面的数据给取出来,取出来要记得释放内存哈,这一步尤其重要。

/*出队列*/int queue_pop(QueueInfo_st *s,ElementType *value){ /*首先判断队列是否为空*/ if(queue_is_empty(s)) return FAILURE; /*找出队列顶元素*/ *value = s->next->value; /*保存等下需要free的指针*/ QueueInfo_st *temp = s->next; /*更换队列顶的位置*/ s->next = s->next->next;
/*释放队列顶节点内存*/ if(temp!=NULL)/*先判断指针是否为空*/ free(temp); temp = NULL;
return SUCCESS;}

源码例程

#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <stdbool.h>
typedef int32_t ElementType; /*队列元素类型*/#define SUCCESS 0#define FAILURE -1
/*定义队列结构*/typedef struct QueueInfo{ ElementType value; /*队列存储的数据*/ struct QueueInfo *next; /*指向队列的下一个元素*/}QueueInfo_st;
/*函数声明*/QueueInfo_st *createQueue(void);int queue_push(QueueInfo_st *s,ElementType value);int queue_pop(QueueInfo_st *s,ElementType *value);int queue_top(QueueInfo_st *s,ElementType *value);int queue_is_empty(QueueInfo_st *s);
/*创建队列,外部释放内存*/QueueInfo_st *createQueue(void){ QueueInfo_st *queue = (QueueInfo_st *)malloc(sizeof(QueueInfo_st)); if(NULL == queue) { printf("malloc failed\n"); return NULL; } queue->next = NULL; return queue;}/*入队列,0表示成,非0表示出错*/int queue_push(QueueInfo_st *s,ElementType value){ /*用来保存尾部指针*/ QueueInfo_st *temp = (QueueInfo_st *)malloc(sizeof(QueueInfo_st)); if(NULL == temp) { printf("malloc failed\n"); return FAILURE; }
/*找到链表的尾部*/ while(s->next != NULL) { s = s->next; }
temp->value = value; temp->next = s->next; s->next = temp;
return SUCCESS;}/*出队列*/int queue_pop(QueueInfo_st *s,ElementType *value){ /*首先判断队列是否为空*/ if(queue_is_empty(s)) return FAILURE; /*找出队列顶元素*/ *value = s->next->value; /*保存等下需要free的指针*/ QueueInfo_st *temp = s->next; /*更换队列顶的位置*/ s->next = s->next->next;
/*释放队列顶节点内存*/ if(temp!=NULL)/*先判断指针是否为空*/ free(temp); temp = NULL;
return SUCCESS;}/*访问队列顶元素*/int queue_top(QueueInfo_st *s,ElementType *value){ /*首先判断队列是否为空*/ if(queue_is_empty(s)) { return FAILURE; } *value = s->next->value; return SUCCESS;}/*判断队列是否为空,空返回1,未空返回0*/int queue_is_empty(QueueInfo_st *s){ /*队列顶指针为空,则队列为空*/ if(s->next == NULL) { printf("队列为空\n"); return true; }
return false;}
int main(void){ int i = 0; int data = 0; QueueInfo_st * queue; queue = createQueue(); for(i = 0 ;i< 20;i++) { queue_push(queue,i); } for(i = 0;i<20;i++) { data = 0; queue_pop(queue,&data); printf("%d \n",data); }}


总结

队列是基本的数据结构,考试和笔试应该会经常遇到,希望大家在面试的时候,还是能随手就写出一个队列,秒杀其他同学,在实际项目中还需要了解环形队列,也是先进先出的队列,但是环形队列它还体现在环上,我们上面建立的队列是没有大小限制的,但是环形队列是有大小限制的,如果插入的数据大于环形队列的大小,就会把第一个数据给覆盖,或者插入失败,至于是什么逻辑,都是代码实现的,都要去看代码理解其中的原理。

附加题(使用C++实现栈)

关于这个附加题,我想起来我有一个邻居,他女儿现在是小学一年级,班里面的同学读书都非常厉害,如果考试考个90分以下的,基本就是班级里面的倒数了,现在的行业竞争非常激烈,小学也是一样,你们以为考试考100分就是第一名了吗?那么你就是真的想多了,考试考105分都是并列几个第一名的,所以我们这个题目也是一样,使用C++来实现一个栈,这个跟上一次的文章刚好呼应,体现了几个问题,一个是C 和C++的不同,通过面向对象的思想实现栈,代码会少很多,而且封装也很好。对于初学者也可以理解类的思想,构造函数和析构函数等等。

这个代码就无偿奉献给大家,希望这个附加题让大家比其他同学多5分。

#include <iostream>using namespace std;
class Stack{ /*struct 默认数据成员是公有的。*/ struct Link { int data_; struct Link *next_; /*结构体也是类,也可以定义构造函数 */ Link(int data,Link *next):data_(data),next_(next) { cout << "Link()"<<endl; } /*结构体也是类,也可以定义析构函数 */ ~Link() { cout << "~Link()"<<endl; } };public: /*栈成员变成初始化,在构造函数中完成 */ Stack(); ~Stack(); void push(const int data); bool empty(); bool pop(int &data);
private: Link * head_; int size_; };
/*c++ NULL = 0 c:(void *)0 c++:0*/Stack::Stack():head_(0),size_(0){ cout << "Stack()"<<endl;}Stack::~Stack(){ cout << "~Stack()"<<endl; Link * tmp; /*循环遍历指针,依次释放内存空间*/ while(head_) { tmp = head_; head_ = head_->next_; delete tmp; cout <<"~Stack() delete stack"<<endl; }}
/*压栈*/void Stack::push(const int data){ /*把栈的头赋值给 node 的next 指针,相当于node->next_= head_*/ Link* node = new Link(data,head_); /*head 时刻保持自己在栈顶上*/ head_ = node; ++size_; }
/*判断栈是否为空*/bool Stack::empty(){ if(size_ == 0) return true; else return false;}

/*c++ 有引用 ,关于引用和指针的区别可以自行百度,对于每个定义大家最好都要有所了解*//*int& r = i; 这个是声明引用变量 *//*int *p = &i; 这个是声明指针变量 *//* 引用是给原来的变量地址取一个新的别名,指针存的是一个变量地址 */bool Stack::pop(int &data){ if(empty() == true) { cout << "stack empty"<<endl; return false; } /*把head_指向的data_取出来,这个是栈的头部*/ Link * tmp = head_; data = head_->data_; head_ = head_->next_; delete tmp; -- size_; return true;}
int main(void){ cout << "Entering main ... "<<endl; Stack *stack = new Stack(); int i; int data = 0; for(i = 0;i<5;i++) { stack->push(i); } for(i = 0;i<3;i++) { stack->pop(data); cout<< data << endl; }
cout << endl; delete stack; cout << "Exiting main ... "<<endl; return 0;}



猜你喜欢:

C语言代码优化的一些技巧(四)

【数据结构笔记】头插法与尾插法创建单链表

基于Linux、C、JSON、Socket的编程实例(附代码)



    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存