数据结构与算法之队列表示与操作实现

330 阅读5分钟

前情回顾

 栈的思想应用

利用栈的特性(先进先出)去解决问题,都有哪些问题适合用栈思想来解决:

  • 数据是线性的
  • 问题中涉及到数据的来回比较,匹配问题,比如:括号匹配,每日温度,字符串解码,去重复字母等
  • 涉及到数据的转置,比如进制问题,链表倒序打印
  • 栈思想不是万能的,它只是一个解决问题的思想,需要具体问题具体分析

 队列模块

顺序储存解决队列结构

typedef struct{   
    QElemType data[MAXSIZE];   
    int front;        /* 头指针 */   
    int rear;        /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
}SqQueue;

初始化一个空队列

Status InitQueue(SqQueue *Q){   
    Q->front = 0;    
    Q->rear = 0;  
  return OK;
}

队列清空

Status ClearQueue(SqQueue *Q){ 
   Q->front = Q->rear = 0; 
   return OK;
}

判断队列是否为空

Status QueueEmpty(SqQueue Q){    
   //队空标记   
    if (Q.front == Q.rear)      
      return TRUE;   
    else      
      return FALSE;
}

队列长度

  • 返回Q的元素个数,也就是队列的当前长度

int QueueLength(SqQueue Q){  
    return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

队头

  • 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR;

Status GetHead(SqQueue Q,QElemType *e){  
    //队列已空   
    if (Q.front == Q.rear)      
       return ERROR;  
    *e = Q.data[Q.front];  
    return OK;
 }

入队

  • 若队列未满,则插入元素e为新队尾元素

Status EnQueue(SqQueue *Q,QElemType e){  
     //队列已满   
     if((Q->rear + 1) % MAXSIZE == Q->front)   
         return ERROR;    //将元素e赋值给队尾   
         Q->data[Q->rear] = e;    //rear指针向后移动一位,若到最后则转到数组头部;   
         Q->rear = (Q->rear + 1) % MAXSIZE;  
     return OK;
}

出队

  • 若队列不空,则删除Q中队头的元素,用e返回值

Status DeQueue(SqQueue *Q,QElemType *e){   
      //判断队列是否为空   
      if (Q->front == Q->rear) {
          return ERROR;  
       } 
    
      //将队头元素赋值给e  
      *e = Q->data[Q->front];    //front 指针向后移动一位,若到最后则转到数组头部  
  
      Q->front = (Q->front + 1) % MAXSIZE;   
  return OK;
}

遍历队列

  • 从队头到队尾依次对队列的每个元素数组

Status QueueTraverse(SqQueue Q){ 
     int i;    
     i = Q.front;   
     while ((i + Q.front) != Q.rear) {  
         printf("%d   ",Q.data[i]);      
         i = (i + 1) % MAXSIZE;   
       }    
      printf("\n");   
  return OK;
}

main 函数打印

int main(int argc, const char * argv[]) {   
    printf("-顺序队列表示与操作实现\n");   
    Status j;    
    int i=0,l;
    QElemType d;   
    SqQueue Q;  
    InitQueue(&Q);   
    printf("初始化队列后,队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));   
    printf("入队:\n"); 
    while (i < 10) {   
        EnQueue(&Q, i);      
        i++;   
    }    
    
    QueueTraverse(Q);   
    printf("队列长度为: %d\n",QueueLength(Q));  
    printf("现在队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
    printf("出队:\n");   //出队
    DeQueue(&Q, &d);   
    printf("出队的元素:%d\n",d);  
    QueueTraverse(Q);   


    //获取队头   
    j=GetHead(Q,&d);   
    if(j)        
    printf("现在队头元素为: %d\n",d);  
    ClearQueue(&Q);   
    printf("清空队列后, 队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));  
   return 0;
}

打印结果:



链式队列操作实现

队列的链表结构, Q.rear 队头-->队尾


队列的链表结构

  /* 结点结构 */
typedef struct QNode  {  
  QElemType data;   
  struct QNode *next;
}QNode,*QueuePtr;

/* 队列的链表结构 */
typedef struct{   
   QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;

链式队列初始化

Status InitQueue(LinkQueue *Q){   
    //1. 头/尾指针都指向新生成的结点   
    Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));   
    //2.判断是否创建新结点成功与否    
    if (!Q->front) {     
        return ERROR;  
     }   

     //3.头结点的指针域置空   
     Q->front->next = NULL;    
   return OK;
}

销毁队列

  • 遍历整个队列,销毁队列的每个结点

Status DestoryQueue(LinkQueue *Q){   
    //遍历整个队列,销毁队列的每个结点   
     while (Q->front) {       
         Q->rear = Q->front->next;  
         free(Q->front); 
         Q->front = Q->rear; 
      }   
   return OK;
}

将队列Q置空

Status ClearQueue(LinkQueue *Q){  
     QueuePtr p,q;   
     Q->rear = Q->front;  
     p = Q->front->next;  
     Q->front->next = NULL;  
     while (p) {     
        q = p;      
        p = p->next;     
        free(q);   
      }    
   return OK;
}

判断队列Q是否为空

Status QueueEmpty(LinkQueue Q){   
     if (Q.front == Q.rear)    
         return TRUE;    
     else  
         return FALSE;
}

获取队列长度

int QueueLength(LinkQueue Q){  
    int i= 0;   
    QueuePtr p;
    p = Q.front;

    while (Q.rear != p) {   
        i++;    
        p = p->next;   
    }    
  return i;
}

插入元素e为队列Q的新元素

Status EnQueue(LinkQueue *Q,QElemType e){     
   //为入队元素分配结点空间,用指针s指向;  
    QueuePtr s = (QueuePtr)malloc(sizeof(QNode));  

   //判断是否分配成功    
    if (!s) {      
      return ERROR;
    }
    
    //将新结点s指定数据域.
    s->data = e;
    s->next = NULL;
    
    //将新结点插入到队尾
    Q->rear->next = s;
    
    //修改队尾指针
    Q->rear = s;
    
    return OK;
}

出队列

Status DeQueue(LinkQueue *Q,QElemType *e){    
     QueuePtr p;   

     //判断队列是否为空;   
     if (Q->front == Q->rear) {    
         return ERROR;   
     }


     //将要删除的队头结点暂时存储在p   
      p = Q->front->next;    

     //将要删除的队头结点的值赋值给e   
      *e = p->data;

     //将原队列头结点的后继p->next 赋值给头结点后继  
      Q->front->next = p ->next;

     //若队头就是队尾,则删除后将rear指向头结点.   
      if(Q->rear == p) Q->rear = Q->front;    
      free(p);

     return OK;
}


获取队头元素

Status GetHead(LinkQueue Q,QElemType *e){  
      //队列非空    
     if (Q.front != Q.rear) {
         //返回队头元素的值,队头指针不变  
         *e = Q.front->next->data;    
         return TRUE;   
     }  
   return  FALSE;
}

遍历队列

Status QueueTraverse(LinkQueue Q){  
     QueuePtr p;   
     p = Q.front->next;  
     while (p) {       
         printf("%d ",p->data);      
         p = p->next;  
      }    
     
     printf("\n");   
     return OK;
}


mian 函数打印

int main(int argc, const char * argv[]) {  
    printf("链队列的表示与操作!\n");     

    Status iStatus;    
    QElemType d;   
    LinkQueue q;

    //1.初始化队列q    
    iStatus = InitQueue(&q);


    //2. 判断是否创建成  
    if (iStatus) {     
        printf("成功地构造了一个空队列\n");   
    }   

     //3.判断队列是否为空   
     printf("是否为空队列?%d (1:是 0:否)\n",QueueEmpty(q)); 

     //4.获取队列的长度   
     printf("队列的长度为%d\n",QueueLength(q)); 
 
     //5.插入元素到队列中  
     EnQueue(&q, -3);  
     EnQueue(&q, 6);   
     EnQueue(&q, 12);
     printf("队列的长度为%d\n",QueueLength(q));
     printf("是否为空队列?%d (1:是 0:否)\n",QueueEmpty(q));      

     //6.遍历队列   
     printf("队列中的元素如下:\n");  
     QueueTraverse(q);

     //7.获取队列头元素   
     iStatus = GetHead(q, &d);   
     if (iStatus == OK) {     
         printf("队头元素是:%d\n",d);   
     }       
   
    //8.删除队头元素   
     iStatus =DeQueue(&q, &d);   
     if (iStatus == OK) {    
         printf("删除了的队头元素为:%d\n",d);
     }

     //9.获取队头元素   
     iStatus = GetHead(q, &d); 
     if (iStatus == OK) {  
        printf("新的队头元素为:%d\n",d);  
     }  
 
     //10.清空队列 
     ClearQueue(&q);  
  
     //11.销毁队列  
     DestoryQueue(&q);

    return 0;
}

打印结果: