linux笔记-数据结构——队列

基本概念

队列是最常见的概念,日常生活经常需要排队,仔细观察队列会发现,队列是一种逻辑结构,是一种特殊的线性表。特殊在:

  • 只能在固定的两端操作线性表

只要满足上述条件,那么这种特殊的线性表就会呈现一种“先进先出”的逻辑,这种逻辑就被称为队列。

由于约定了只能在线性表固定的两端进行操作,于是给队列这种特殊的线性表的插入删除,起个特殊的名称:

  • 队头:可以删除节点的一端
  • 队尾:可以插入节点的一端
  • 入队:将节点插入到队尾之后,函数名通常为enQueue()
  • 出队:将队头节点从队列中剔除,函数名通常为outQueue()
  • 取队头:取得队头元素,但不出队,函数名通常为front()

由于这种固定两端操作的简单约定,队列获得了“先进先出”的基本特性,如下图所示:

顺序存储的队列:循环队列

与其他的逻辑结构类似,队列可以采用顺序存储形成循环队列,也可以采用链式存储形成链式队列。顺序存储的队列之所以被称为循环队列,是因为可以利用更新队头队尾的下标信息,来循环地利用整个数组,出队入队时也不必移动当中的数据。循环队列示意图如下所示:

图中可以观察到,需要牺牲至少数组中的一个存储位置,来区分循环队列中的满队和空队。满队和空队的约定如下:

  • 当front与rear相等时,队列为空
  • 当rear循环加一与front相等时,队列为满

与其他数据结构一样,管理循环队列除了需要一块连续的内存之外,还需要记录队列的总容量、当前队列的元素个数、当前队头、队尾元素位置,如果有多线程还需要配互斥锁和信号量等信息,为了便于管理,通常将这些信息统一于在一个

管理结构体之中:

struct seqQueue { 
datatype *data; // 循环队列入口
 int capacity; // 循环队列总容量 
int front; // 循环队列队头元素下标 
int rear; // 循环队列队头元素下标 
};

初始化循环队列:

P_Cntl queueInit( int size )
 {     // 先分配管理结构体的内存空间     
P_Cntl cntl = calloc(1, sizeof(Cntl));     // 初始化管理结构体的成员        
 // 初始化入口地址     
cntl->ptr = calloc( size , sizeof(datatype) );         // 初始化大小等信息     
cntl->capacity = size ;     
cntl->front = cntl->rear = 0 ;  // 队头等于队尾, 队伍为空        
 return cntl ; 
}

入队:

bool enQueue( P_Cntl cntl , datatype * data )
 {     //  判断队列是否为满,     //    
(队尾下标   + 1  )对  容量取余     ==   对头下标     
if ((cntl->rear + 1)% cntl->capacity == cntl->front )     
{         printf("当前队列为满 ....\n");         
return false ;     
}         // 入队     
memcpy( cntl->ptr+cntl->rear , data , sizeof(datatype) );     // 队尾后移    
 cntl->rear = (cntl->rear +1 ) % cntl->capacity ;     
return true ; 
}

出队:

datatype * outQueue( P_Cntl cntl ) 
{     // 判断队伍是否为空     
if (cntl->rear == cntl->front)     
{         printf("队伍为空 。。。。\n");        
 return NULL ;     
}     // 申请一个堆空间用来存放出队的数据     
datatype * del = calloc(1, sizeof(datatype));     
// 把队头数据拷贝到 del 内存中     
memcpy( del , cntl->ptr+cntl->front , sizeof(datatype) );    
 // 队头循环+1     
cntl->front = (cntl->front+1) % cntl->capacity ;     
return del ; 
}

链式存储的队列:链式队列

链式队列的组织形式与链表无异,只不过插入删除被约束在固定的两端。为了便于操作,通常也会创建所谓管理结构体,用来存储队头指针、队尾指针、队列元素个数等信息:

从上图可以看到,链式队列主要控制队头和队尾,由于管理结构体中保存了当前队列元素个数size,因此可以不必设计链表的头节点,初始化空队列时只需要让队头队尾指针同时指向空即可。

不使用管理结构体示例:

结点设计:

typedef int dataType; // 设计链表中结点的结构体 ( 结点设计 ) 
typedef struct list_Queue 
{    
 /* data */    
 dataType data ;    
 // 指针域     
struct list_Queue * next ; 
} Node , *P_Node ;

初始化:

P_Node init_Node( dataType * data  ) 
{     
P_Node new = calloc(1, sizeof (Node)) ;    
if (data != NULL )     
{        
memcpy( new->data , data , sizeof(dataType) );     
}     
new->next =  NULL ;       
return new ; 
}

入队:

bool enQueue( P_Node head , dataType * p_data ) 
{     
if (head == NULL )     
{         printf("队头异常...\n");         
return false ;    
 }         
// 入队选择使用尾插    
 P_Node tmp;     
for ( tmp = head ; tmp->next == NULL ; tmp = tmp->next );    
 // 创建新结点     
P_Node new = init_Node( p_data  );     
// 把新结点插入到队尾     
new->next = tmp->next ;     
tmp->next = new ;     
return true ; 
}

出队:

P_Node outQueue( P_Node head ) 
{     if ( head->next ==  NULL  )    
 {         printf("当前队列为空....\n");        
 return NULL ;     
}     // 剔除链表的第一个结点     
P_Node del = head->next ;     
head->next = del->next ;     
del->next = NULL ;    
 return del; 
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值