[データ構造学習記録9]-双方向キュー

I.概要

キューの特別な構造のため、通常、前のセクションのようにチェーンリストを使用します。ただし、シーケンス構造にはシーケンス構造の利点がある場合があるため、シーケンステーブルを使用して何らかの方法でリストを実装することもできます。これは、循環キューによって実現されます。

2.原則の実現

1.ノード

これはシーケンシャル構造であるため、ノードは他のものを必要とせず、データを格納するだけで済みます。

2.循環キュー構造

循環キューの特別なメカニズムのため、通常、キューの拡張は考慮されません。次に、固定長にする必要がありMaxSizeます。3つの部分で構成されたキューので基址*basefront头指针tail尾指针ループであるため、テールポインタの値がヘッドポインタの前にある可能性があります。たとえばMaxSize=6 front=4 tail=2、キューの長さは4 5 0 1これらの4つの位置である必要があるため、計算すると、になります(tail-front+MaxSize)%Maxsize

3.キューの初期化と空のキューの判断

キューが初期化され、*baseストレージスペースが動的直接生成されてから、ストレージスペースが生成されfront=tail=0ます。空のキューの場合は、そのためですfront=tail
ここに画像の説明を挿入

4.キューがいっぱいであるという判断

私たちのキューはいっぱいです、最初の終わりの前に2つのケースがあります:tail=MaxSize-1、;最初front=0の終わりの前にあるケースの関数があります:tail+1=frontしたがって、要約すると、その判断はである必要があります(tail+1)%MaxSize=front

5.キューの登録

チームに参加するにはtail、値を挿入した場所を書き込むだけで状況++tailが発生する可能性があるtail+1=MaxSizeため、1つを使用するif计算、その値を変更する必要があります。個人的には計算を使用することをお勧めしますtail = (tail+1)%MaxSizeしかし、理論的には、ifを使用して更新しても問題はありません。ただし、快慢指针この方法を使用して問題を解決する場合もあるため、この計算方法のフォールトトレランス率ははるかに優れている可能性があります。
しかし、我々はキューが満杯であるかどうかをまず判断し、キューに格納されている要素の最大数がなる場合なおMaxsize-1ので、tailそれは常にある尾元位置、それが直接利用可能である、との判断がいっぱいですtail+1=front最後の要素を使用することはできませんので、 。次の図に示すように、チームが満員であると判断する方法を変更しない限り、J8は実際にはデータがないはずだからです。
ここに画像の説明を挿入

6.デキュー

デキューはエンキューに似ていますが、順序構造のアドレスに対して何もする必要はなく、ヘッドポインタを配置するだけで済みますfront+1もちろん、MaxSize超える場合あるため、いくつかのフォールトトレランスメカニズムを採用する必要があります。front = (front+1)%MaxSize

3.コードの実装

#include <stdio.h>
#include <stdlib.h>

#define ERROR       0
#define OK          1
#define OverFlow    2
#define MaxSize     5

typedef struct dataType{
    
    
    int data;
}dataType;

typedef struct cqueue{
    
    
    dataType *base;
    int front;
    int tail;
}cqueue;

cqueue* CqueueInit(void);
int CqueuePush(cqueue* q, dataType data);
int CqueueGet(cqueue *q, dataType *data);
int CqueuePop(cqueue *q);
int CqueueShow(cqueue *q);

int main()
{
    
       
    // 主函数随便改
    cqueue *q = CqueueInit();
    dataType test;
    test.data = 0;
    CqueuePush(q,test);
    test.data = 1;
    CqueuePush(q,test);
    test.data = 2;
    CqueuePush(q,test);
    test.data = 3;
    CqueuePush(q,test);
    CqueuePop(q);
    test.data = 4;
    CqueuePush(q,test);
    CqueueShow(q);
    return 0;
}

cqueue* CqueueInit(void)
{
    
    
    cqueue *q = (cqueue*)malloc(sizeof(cqueue));
    dataType *data = (dataType*)malloc(sizeof(dataType)*MaxSize);
    if (q != NULL && data != NULL)
    {
    
    
        q->base = data;
        q->front = 0;
        q->tail = 0;    // 初始化循环队列
        return q;
    }
    exit(0);
}

int CqueuePush(cqueue* q, dataType data)
{
    
    
    if ((q->tail+1)%MaxSize == q->front) return OverFlow;
    // 注意这样的写法会导致最后有一个节点存不到数据
    *(q->base+q->tail) = data;
    q->tail += 1;   
    return OK;
}

int CqueueGet(cqueue *q, dataType *data)
{
    
    
    if ((q->tail - q->front)%MaxSize == 0)
    {
    
    
        return ERROR;   
    }
    else
    {
    
    
        *data = *(q->base+q->tail);     //  返回头指针指向的值
        return OK;
    }
}

int CqueuePop(cqueue *q)
{
    
    
    q->front += 1;      // 更新一下指向的元素
    return OK;
}

int CqueueShow(cqueue *q)   // 这个函数就打印一下队列 看看效果
{
    
    
    int start,end = 0;
    int cont = 0;
    if (q->tail < q->front) // 队尾在队头的前面
    {
    
    
        end = q->tail + MaxSize;    
    }
    else
    {
    
    
        end = q->tail;  // 队头在队尾的前面
    }
    for(start = q->front; start < end; ++start)
    {
    
    
        printf("No.%d data is %d\n", cont, (q->base+start)->data);
        ++cont;
    }
}

おすすめ

転載: blog.csdn.net/u011017694/article/details/109459539