队列类型的数据结构:
队列类型是一种先进先出的数据结构,只能在队列的头部取出数据,在队尾存入数据。下面介绍两种基于数组实现的队列。给出了队列的操作方法(函数)。
单向队列:
#include"queue.h"
typedef struct{
int buf[SIZE];
int head;//表示最前面的数字所在存储区的下标,如果队列里没有数据的时候,head>应该等于tail
int tail;//下一个数字应该放置的存储区的下标
}queue;
//队列的初始化函数
void queue_init(queue* p_queue){
p_queue->head = 0;
p_queue->tail = 0;
}
//队列的清理函数
void queue_deinit(queue* p_queue){
p_queue->head = 0;
p_queue->tail = 0;
}
//获得队列个数的函数
int queue_size(const queue* p_queue){
return p_queue->tail - p_queue->head;
}
//判断队列是否满的函数
int queue_full(const queue* p_queue){
if (p_queue->tail >= SIZE)
return 1;
else
return 0;
}
//判断队列是否空的函数
int queue_empty(const queue* p_queue){
if(p_queue->head == p_queue->tail)
return 1;
else
return 0;
}
//向队列里加入数字的函数
int queue_push(queue* p_queue,int value){
if(queue_full(p_queue))
return 0;
p_queue->buf[p_queue->tail] = value;
p_queue->tail += 1;
return 1;
}
//从队列里获得数字的函数
int queue_pop(queue* p_queue,int* p_value){
if(queue_empty(p_queue))
return 0;
*p_value = p_queue->buf[p_queue->head];
p_queue->head += 1;
return 1;
}
//从队列获得一个数字,但不删除
int queue_front(const queue* p_queue,int* p_value){
if(queue_empty(p_queue))
return 0;
*p_value = p_queue->buf[p_queue->head];
return 1;
}
循环队列:
循环队列的要点在于怎么处理队列头和尾的循环,在以下代码中,通过在每次对队列头下标值累加的时候判断其是否超出了队列长度,如果超出就将队列的头和尾的下标减去队列长度,确保队列头和尾的下标值不会超过int类型的上限(头和尾是一直累加的,如果不管,多次循环之后必定超出int类型上限)。
#include"queuep.h"
typedef struct{
int num[SIZE];
int head;
int tail;
}queuep;
//初始化队列
void queuep_init(queuep* p_queue){
p_queue->head = 0;
p_queue->tail = 0;
}
//清除队列
void queuep_deinit(queuep* p_queue){
p_queue->head = 0;
p_queue->tail = 0;
}
//计算队列当前的长度
int queuep_size(const queuep* p_queue){
return p_queue->tail - p_queue->head;
}
//判断当前队列是否为满
int queuep_full(const queuep* p_queue){
if((p_queue->tail - p_queue->head) == SIZE)
return 1;
else
return 0;
}
//判断当前队列是否为空
int queuep_empty(const queuep* p_queue){
if(p_queue->head == p_queue->tail)
return 1;
else
return 0;
}
//向队尾填入数据
int queuep_push(queuep* p_queue,int value){
if(queuep_full(p_queue))
return 0;
//这里对队尾的下标取余是为了保证,当队尾下标超出SIZE之后还是可以正常存入数据
p_queue->num[p_queue->tail % SIZE] = value;
p_queue->tail++;
return 1;
}
//从队列头部弹出数据
int queuep_pop(queuep* p_queue,int* p_value){
if(queuep_empty(p_queue))
return 0;
//这里对队列头部的取余,其实是没有必要的,一旦上一次的取值使得头部下标超出数组长度,那么就会被下面的代码重置,但是为了保证代码的一致性,还是写上好了。
*p_value = p_queue->num[p_queue->head % SIZE];
p_queue->head++;
if(p_queue->head == SIZE){
p_queue->tail -= SIZE;
p_queue->head -= SIZE;
}
return 1;
}
//从队列头部获得数据,但是不弹出
int queuep_front(const queuep* p_queue,int* p_value){
if(queuep_empty(p_queue))
return 0;
*p_value = p_queue->num[p_queue->head%SIZE];
return 1;
}
链表类型的数据结构
链表的类型,其实是由一个个节点组成的,链表自身的结构体只记录链表的头尾节点。每个节点中,记录了当前节点内存放的数据和指向下一个节点的节点指针。
当然,也可以在节点的结构体中加入记录前一个节点的指针。如果这样做,那么一个节点里记录前一个节点的地址和后一个节点的地址,就变成了双向链表。
双向链表的优势在于,对链表尾部处理的时候,不需要从链表的头节点遍历到链表尾部,再处理,而是可以通过节点的前向指针,直接从尾部开始处理。
下面提供操作双向链表的方法(函数)
//链表初始化
void link_init(link* p_link){
p_link->head.p_next = &(p_link->tail);
p_link->head.p_prev = NULL;
p_link->tail.p_prev = &(p_link->head);
p_link->tail.p_next = NULL;
p_link->p_cur = NULL;
}
//清理链表
void link_deinit(link* p_link){
p_link->p_cur = NULL;
while(p_link->head.p_next != &(p_link->tail)){
node* p_first = &(p_link->head);
node* p_mid = p_first->p_next;
node* p_last = p_mid->p_next;
p_first->p_next = p_last;
p_last->p_prev = p_first;
free(p_mid);
p_mid = NULL;
}
}
//获得链表里数据个数
int link_size(const link* p_link){
int count = 0;
const node* temp = {0};
temp = &(p_link->head);
while(temp->p_next != &(p_link->tail)){
count++;
temp = temp->p_next;
}
return count;
}
//判断链表是否空的函数
int link_empty(const link* p_link){
if(p_link->head.p_next == &(p_link->tail))
return 1;
return 0;
}
//判断链表是否满的函数
int link_full(const link* p_link){
return 0;
}
//插入在最前面擦入新数据的函数
int link_add_head(link* p_link,int value){
node* p_first = NULL,*p_mid = NULL,*p_last = NULL;
node* p_node = NULL;
p_link->p_cur = NULL;
p_node = (node*)malloc(sizeof(node));
if(!p_node) return 0;
p_node->num = value;
p_node->p_next = NULL;
p_node->p_prev = NULL;
p_first = &(p_link->head);
p_mid = p_first->p_next;
p_last = p_mid->p_next;
p_node->p_next = p_mid;
p_mid->p_prev = p_node;
p_node->p_prev = p_first;
p_first->p_next = p_node;
return 1;
}
//在最后面加入新数字的函数
int link_add_tail(link* p_link,int value){
node* p_first = NULL,*p_mid = NULL,*p_last = NULL,*p_temp = NULL;
node* p_node = NULL;
p_link->p_cur = NULL;
p_node = (node*)malloc(sizeof(node));
if(!p_node) return 0;
p_node->num = value;
p_node->p_next = NULL;
p_node->p_prev = NULL;
p_first = p_link->tail.p_prev;
p_mid = p_first->p_next;
p_last = p_mid->p_next;
p_first->p_next = p_node;
p_node->p_prev = p_first;
p_node->p_next = p_mid;
p_mid->p_prev = p_node;
return 1;
}
//在链表里按顺序插入新数字的函数
int link_insert(link* p_link,int value){
node* p_first = NULL,*p_mid = NULL,*p_last = NULL,*p_temp = NULL;
node* p_node = NULL;
p_link->p_cur = NULL;
p_node = (node*)malloc(sizeof(node));
if(!p_link) return 0;
p_node->num = value;
p_node->p_next = NULL;
p_node->p_prev = NULL;
for(p_temp = &(p_link->head);p_temp != &(p_link->tail);p_temp = p_temp->p_next){
p_first = p_temp;
p_mid = p_first->p_next;
p_last = p_mid->p_next;
if(((p_first->num < p_node->num) && (p_mid->num > p_node->num)) || p_mid == &(p_link->tail)){
p_first->p_next = p_node;
p_node->p_prev = p_first;
p_node->p_next = p_mid;
p_mid->p_prev = p_node;
break;
}
}
return 1;
}
//删除最前面有效节点的函数
int link_remove_head(link* p_link){
p_link->p_cur = NULL;
if(link_empty(p_link)) return 0;
node* p_first = &(p_link->head);
node* p_mid = p_first->p_next;
node* p_last = p_mid->p_next;
p_first->p_next = p_last;
p_last->p_prev = p_first;
free(p_mid);
p_mid = NULL;
return 1;
}
//删除最后面有效节点的函数
int link_remove_tail(link* p_link){
p_link->p_cur = NULL;
if(link_empty(p_link)) return 0;
node* p_last = &(p_link->tail);
node* p_mid = p_last->p_prev;
node* p_first = p_mid->p_prev;
p_first->p_next = p_last;
p_last->p_prev = p_first;
free(p_mid);
p_mid = NULL;
return 1;
}
//删除顺序链表中的某个值的节点
int link_remove(link* p_link,int value){
p_link->p_cur = NULL;
if(link_empty(p_link)) return 0;
node* p_temp = {0};
for(p_temp = &(p_link->head);p_temp != &(p_link->tail);p_temp = p_temp->p_next){
node* p_first = p_temp;
node* p_mid = p_first->p_next;
node* p_last = p_mid->p_next;
if(p_mid->num == value && p_mid != &(p_link->tail)){
p_first->p_next = p_last;
p_last->p_prev = p_first;
free(p_mid);
p_mid = NULL;
return 1;
}
}
return 0;
}
//从链表里获得第一个数字的函数
int link_get_head(const link* p_link,int* value){
if(link_empty(p_link)) return 0;
const node* p_first = &(p_link->head);
const node* p_mid = p_first->p_next;
const node* p_last = p_mid->p_next;
*value = p_mid->num;
return 1;
}
//从链表末尾获得一个数字
int link_get_tail(const link* p_link,int* value){
if(link_empty(p_link)) return 0;
const node* p_last = &(p_link->tail);
const node* p_mid = p_last->p_prev;
const node* p_first = p_mid->p_prev;
*value = p_mid->num;
return 1;
}
//根据下标获得一个数字
int link_get(const link* p_link,int num,int* value){
int count = 0;
const node* p_temp = {0};
if(link_empty(p_link)) return 0;
for(p_temp = &(p_link->head);p_temp != &(p_link->tail);p_temp = p_temp->p_next){
const node* p_first = p_temp;
const node* p_mid = p_first->p_next;
const node* p_last = p_mid->p_next;
if(num == count && p_mid != &(p_link->tail)){
*value = p_mid->num;
return 1;
}
count++;
}
return 0;
}
//开始从前向后遍历所有节点
void link_begin(link* p_link){
p_link->p_cur = &(p_link->head);
}
//在遍历过程中,获得下一个节点里的数字
int link_next(link* p_link,int* p_value){
if(p_link->p_cur == NULL) return 0;
p_link->p_cur = p_link->p_cur->p_next;
if(p_link->p_cur == &(p_link->tail)){
p_link->p_cur = NULL;
return 0;
}
else{
*p_value = p_link->p_cur->num;
return 1;
}
}