資料結構C語言|佇列相關

Hane820發表於2024-10-19

佇列

普通佇列與迴圈佇列:
結構體
初始化佇列
判斷隊空
入隊
出隊
檢查隊滿
迴圈佇列

鏈式佇列:
鏈式佇列
鏈式佇列結構
初始化
判斷是否為空
入隊
出隊
遍歷
全部程式碼展示

結構體

typedef int ElemType;
#define MaxSize 10
typedef struct{
	ElemType data[MaxSize];   
	//用靜態陣列存放佇列元素
	int front,rear;           
	//定義隊頭指標和隊尾指標
}SqQueue;
//Sq-----sequence順序

  • 隊頭指標front————指向隊頭元素

  • 隊尾指標rear————指向隊尾元素的後一個位置(下一個應該插入的位置)

    返回標題

初始化佇列

我是隊 data[3] ←我是rear指標
我是隊 data[2]
我是隊 data[1]
我是隊 data[0] ←我是front指標
//函式功能:初始化佇列
void InitQueue(SqQueue *Q){
	//初始時,隊頭和隊尾指標都指向0;
	Q->rear=Q->front=0;
}

void testQueue(){
	SqQueue Q;     //宣告一個佇列(順序儲存)————這段語句執行後,
	//就會在記憶體中分配連續大小為MaxSize*sizeof(ElemType)的空間
}

初始化時↓

我是front指標→ data[0] 我是隊 ←我是rear指標
font和rear指向同一個地方。

返回標題

判斷隊空


#include <stdbool.h>
#define MaxSize 10
typedf struct{
	Elemtype data[MaxSize];   
	//用靜態陣列存放佇列元素
	int front,rear;           
	//定義隊頭指標和隊尾指標
}SqQueue;
//Sq-----sequence順序

//函式功能:判斷佇列是否為空
bool QueueEmpty(SqQueue Q){
	if(Q.rear==Q.front)  //隊空的條件
		return true;
	else
		return false;
}

該函式判斷了隊頭指標和隊尾指標是否相同,從而來判斷隊是否為空,然鵝這是有侷限性的。我們稍後會再解釋。
返回標題

入隊

#define MaxSize 10
typedf struct{
	Elemtype data[MaxSize];   //用靜態陣列存放佇列元素
	int front,rear;           //定義隊頭指標和隊尾指標
}SqQueue;
//Sq-----sequence順序

//函式功能:入隊
void EnQueue(SqQueue* Q,ElemType x){

    if(QueueEmpty(*Q))

        return false;//報錯

    Q->data[Q->rear]=x;  //將x插入到隊尾

    Q->rear=Q->rear+1;  // 隊尾指標後移

    printf("%d",&x);

}

向Enqueue傳入隊的位置和新元素,判斷一下隊是否可入。如果可入就將新元素入隊。新元素放進隊尾指標指向的位置,再讓隊尾指標指向向後面挪一位。

我想進來
我是front指標→ data[0] 我是隊 ←我是rear指標

進入:

←我是rear指標
我是front指標→ data[0] 我進來了

檢查隊滿

我們能不能用Q . r e a r = = MaxSize作為佇列滿的條件呢?
答:肯定是不能。
————————————————

分析原因:假設我們透過入隊操縱使得佇列滿使得Q .rear = = M a x S i z e,但是由於我們出隊操作的過程中,隊尾指標不會改變,一直保持Q . r e a r = = M a x S i z e MaxSize,而我們的隊頭指標front一直在變化,就是在這種情況下導致佇列不滿,但Q . r e a r = = M a x S i z e。所以Q . r e a r = = M a x S i z e 不能作為佇列滿的判斷條件。
————————————————

簡單來說,就是會出現隊頭隊尾都指向maxSize的情況,這樣就無法判斷佇列到底是為空還是滿了。

那麼如何判斷隊滿呢?我們可以繼續看迴圈佇列。
返回標題

迴圈佇列

迴圈佇列與取模運算


//函式功能:入隊
bool EnQueue(SqQueue &Q,ElemType x){
	if(佇列已滿)
		return false;//報錯
	Q.data[Q.rear]=x;  //將x插入到隊尾
	Q.rear=(Q.rear+1)%MaxSize;  // 隊尾指標加一取模
	//這個語句的操作,
	//使得Q.rear的取值範圍固定在了{0,1,2,3,...,MaxSize-1}。
	//可以理解將儲存空間變成了“環狀”。
	return ture;
}

假設隊伍容量為5;
1%5=1;2%5=2;3%5=3;
4%5=4;5%5=0;6%5=1;
餘數一直在0-4之間迴圈。使得儲存空間和範圍變成了環狀。

這樣我們可以以迴圈佇列的隊尾指標的下一個位置是隊頭來判斷是否隊滿。
但是我們rear指標所指的空間不能使用,因為新增了資料之後,rear會往後挪一格,從而與隊頭指標重合,隊空隊滿的條件再次一致。

判斷隊滿:

bool  QueueFull(SqQueue* Q){

    if((Q->rear+1)%MaxSize==Q->front)//判斷隊空或滿
        { 
          printf("隊滿\n");
            return false;}
            //報錯
        else
        {printf("隊未滿\n");
        return true ;}
}
//函式功能:判斷佇列是否為空
bool QueueEmpty(SqQueue Q){
	if(Q.rear==Q.front)  //隊空的條件
		return true;
	else
		return false;
}
//函式功能:入隊
bool EnQueue(SqQueue*Q,
			 ElemType x){
    //if(佇列已滿)
    if((Q->rear+1)%MaxSize==Q->front)//判斷隊空或滿
        return false;//報錯
    Q->data[Q->rear]=x;  
    //將x插入到隊尾
    Q->rear=(Q->rear+1)%MaxSize;  // 隊尾指標加一取模
    //這個語句的操作,使得Q.rear的取值範圍固定在了{0,1,2,3,...,MaxSize-1}。
    //可以理解將儲存空間變成了“環狀”。
    printf("入隊元素為%d\n",x);
    return true;
}

返回標題

迴圈佇列出隊

//函式功能:出隊——刪除一個隊頭元素,並用x返回
bool DeQueue(SqQueue *Q,ElemType x){
    if(Q->rear==Q->front)
        return false;
        //佇列為空,報錯
    x=Q->data[Q->front];
    //隊頭元素賦值給x;
    Q->front=((Q->front+1)%MaxSize);
    printf("出隊已完成,出隊元素為%d\n",x);
    //隊頭指標加一取模保證在迴圈佇列中隊頭指標後移;
    return true;
}

該函式傳入一個隊的位置,和一個

迴圈佇列的出隊操作類似於順序表的刪除操作,但不同的是佇列只能讓隊頭先出隊。

  • SqQueue &Q:這是對迴圈佇列物件的引用。透過引用傳遞,可以直接修改傳入的佇列物件而無需複製整個佇列,提高了效率。
  • ElemType &x:用於儲存出隊元素的引用引數。出隊成功後,隊頭元素的值將被賦給這個引數。

注意,該函式使用之後只是將一個元素出隊,出隊的元素可以儲存在x中方便我們輸出。
返回標題

迴圈佇列中查詢元素

//函式功能:獲得隊頭元素的值,用x返回。
bool GetHead(SqQueue *Q,ElemType x){
    if(Q->rear==Q->front){
        printf("隊為空,無法出隊");
        return false;
        }
        else {//隊空,無元素,報錯;
    x=Q->data[Q->front];
    printf("隊頭為%d\n",x);
    return true;}
}

可以發現上述程式碼與出隊操作類似。同樣的x這裡起到的作用是方便我們獲取找到的元素。
與出隊相比,這裡僅僅獲取元素,並沒有將元素刪除。
返回標題

**真正的查詢元素

bool searchInCircularQueue(SqQueue*q,int target) {
    int index = q->front;
    while (index!= q->rear) {
        if (q->data[index] == target) {
            return true;
        }
        index = (index + 1) % MaxSize;
    }
        return false;
        }
void  FindElement(SqQueue*q,int target){
   if
   (searchInCircularQueue(q, target)==true) {
        printf("%d 元素在該佇列中.\n", target);
    } else {
        printf("%d 元素不在該佇列中.\n", target);
    }
}

返回標題

一、函式功能

這個函式的目的是在給定的迴圈佇列中查詢特定的目標元素。如果目標元素存在於佇列中,則返回true;否則,返回false

二、引數說明

  • SqQueue * q:這是一個指向迴圈佇列結構體的指標。透過這個指標,可以訪問迴圈佇列的各個成員,包括儲存資料的陣列、隊頭指標front和隊尾指標rear
  • int target:要在佇列中查詢的目標元素值。

三、程式碼邏輯分析

  1. int index = q->front;
    • 初始化一個索引變數index,將其設定為隊頭指標的值。這個索引將用於遍歷迴圈佇列中的元素。
  2. while (index!= q->rear) {... }
    • 這是一個迴圈,只要索引不等於隊尾指標,就會繼續執行迴圈體。這個條件確保在遍歷佇列時不會超出佇列的範圍。
  3. if (q->data[index] == target) { return true; }
    • 在迴圈體內,首先檢查當前索引位置的元素是否等於目標元素。如果相等,說明找到了目標元素,立即返回true
  4. index = (index + 1) % MAX_SIZE;
    • 如果當前元素不等於目標元素,將索引向後移動一位。由於是迴圈佇列,需要使用取模運算% MAX_SIZE來確保索引始終在合法的範圍內。當索引達到陣列的末尾時,取模運算會將其重新設定為陣列的開頭,實現迴圈遍歷。
  5. return false;
    • 如果迴圈結束後還沒有找到目標元素,說明目標元素不在佇列中,返回false

返回標題

其他的思路

關於迴圈佇列隊滿與隊空的區分與判斷,還有其他的處理方式。

  1. 剛剛所述的方法,代價是浪費一個儲存單元。
  2. 在定義型別中,定義一個資料型別成員size,標示元素個數。初始化時,rear=front=0;size=0;隊空的條件是Q。Size= =0;隊滿:Q.size = = MaxSize;判斷條件從頭尾指標變成了size。
#define MaxSize 10
typedf struct{
	Elemtype data[MaxSize];  
	 //用靜態陣列存放佇列元素
	int front,rear;           
	//定義隊頭指標和隊尾指標
	int size;                
	 //佇列當前長度
}SqQueue;
//插入成功,入隊,size++;
//刪除成功,出隊,size--;
  1. 在結構體中增加一個tag,用於區分隊空與隊滿;出隊成功時tag=0;入隊成功時tag=1;而入隊是不會使隊為空的,只有出隊會使隊為空。所以我們可以判斷font= =rear時增加一個判斷tag=0還是tag=1來判斷隊空還是隊滿。
front = =rear&&tag==1;//隊滿
front=  =rear&&tag==0;//隊空

返回標題

遍歷輸出

void printCircularQueue(SqQueue*q) {
    if (QueueEmpty(*q)) {
        printf("Queue is empty.\n");
        return;
    }
    int index = q->front;
    while (index!= q->rear) {
        printf("%d ", q->data[index]);
        index = (index + 1) % MaxSize;
    }
    printf("\n");
}

返回標題

鏈式佇列

返回標題

鏈佇列結構

***一個同時帶有隊頭指標和隊尾指標的單連結串列。頭指標指向隊頭節點,尾指標指向隊尾節點。
因為他同時帶有隊的性質和連結串列的性質,因此鏈式儲存佇列可以分為:帶頭節點的佇列,和不帶頭結點的佇列。

帶頭結點:

head--> 我是隊員--> 我是隊員--> 我是隊員--> NULL

front

rear
不帶頭結點:
我是隊員--> 我是隊員--> 我是隊員--> NULL

front

rear
typedef struct LinkNode{     
//鏈式佇列結點
	ElemType data;
	struct LinkNode *next;
}LinkNode;  

typedef struct LinkQueue{               
//鏈式佇列
	LinkNode *front,*rear;   
	//佇列的隊頭和隊尾指標
}LinkQueue;

LinkNode表示鏈式佇列中的節點;
Link Queue則表示整個鏈式佇列。

返回標題

初始化

帶頭結點的初始化
//函式功能:初始化佇列--帶頭結點
void InitLinkQueue (LinkQueue *Q){
    //初始化時,frony 和rear指標都指向頭結點
    Q->front=Q->rear =(LinkNode*)malloc(sizeof(LinkNode));
    Q->front->next=NULL;
    printf("已初始化一個鏈式佇列");
}
head→ NULL
↑ ↑
front rear
head→ 我是隊員→ 我是隊員→ 我是隊員→ NULL

front

rear
不帶頭結點的初始化
void InitLinkNoHeadQueue (LinkQueue *Q){
     //初始化時,frony 和rear指標都指向NULL
    Q->front = Q->rear = NULL;
    printf("一個不帶頭節點的鏈式佇列已初始化完畢");

}

返回標題

判斷是否為空

帶頭結點:

head-> NULL
↑ ↑
front rear
//判斷佇列是否為空
bool LinkIsEmpty(LinkQueue *Q){
    if(Q->front==Q->rear)
     //其實,只有為空時,Q.front==Q.rear,其他條件也沒必要考慮了。
        {printf("該鏈式佇列為空\n");
            return true;
        }
    else{
        printf("該鏈式佇列不為空\n");.
        return false;
        }
}

不帶頭結點

NULL
↑ ↑
front rear
//判斷佇列是否為空
boolean IsEmpty(LinkQueue Q){
	if(Q.front==NULL)  //
		return true;
	else
		return false;
}

返回標題

鏈式佇列入隊

帶頭結點

//函式功能:帶頭結點佇列新元素入隊--帶頭結點

void EnLinkQueue(LinkQueue *Q,ElemType x){
    LinkNode *newNode =(LinkNode*)malloc(sizeof(LinkNode));//申請一個結點newNode
    newNode->data=x;
    newNode->next=NULL;
    Q->rear->next=newNode;
    //新結點插入到rear之後
    Q->rear=newNode;    
    // 修改表尾指標,入隊操作不需要需要表頭指標front;
    printf("%d已入隊\n",x);
}

傳入鏈式隊的位置和新元素給該函式;他會開闢一個空間,將傳入的x放入該空間的data 部分,next指向null。隊尾rear指向該空間。

我想進來
head-> NULL
↑ ↑
front rear

進來:

head-> 我是空間s NULL
[ date ] * next 我也是空間s

front rear
我是空間s
head-> 我進來了-> NULL
[ date ] * next [ date ] * next

front

rear

不帶頭結點

//函式功能:帶頭結點佇列新元素入隊--不帶頭結點
void EnNoHeadQueue(LinkQueue *Q,ElemType x){

    LinkNode *s =(LinkNode*)malloc(sizeof(LinkNode));
    //申請一個結點s
    s->data=x;
    s->next=NULL;
    if (Q->rear==NULL) {
        Q->front = Q->rear = s;
        printf("元素%d已入隊\n",x);
    } else {
        Q->rear->next = s;
        //新結點插入到rear之後
        Q->rear = s;
        printf("元素%d已入隊\n",x);
        // 修改表尾指標,
        //入隊操作不需要需要表頭指標front;
    }
}

其中加入了一個判斷:如果隊為空(即隊尾指向空),加入的是第一個元素,那麼頭尾都指向他。如果不是第一個元素,那麼加入的元素插入到尾指標。
返回標題

鏈式佇列出隊

帶頭結點

//函式功能:帶頭結點隊頭元素出隊--帶頭結點
bool DeLinkQueue(LinkQueue *Q,ElemType x){
    if(Q->front->next==NULL){
        printf("空佇列,無法出隊\n");
        return false;  
         //空佇列
    }
    LinkNode *temp =Q->front->next;
    //將頭節點的下一個節點儲存到temp,用於取出數值
    x=temp->data;    
    //用變數x返回隊頭元素
    printf("%d已出隊\n",x);
    Q->front->next=temp->next;
    //修改隊頭指標
    if(Q->rear==temp){  
     //考慮最後一個結點出隊的情況
        Q->rear=Q->front;
        //修改rear指標
        printf("%d已出隊這是隊中最後一個元素\n",x);
    }
    free(temp)
     //釋放結點空間
    return true;
}

同樣的,給該函式輸入一個隊的位置和一個x變數用於儲存出隊的元素,呼叫該函式一次出隊一個。
返回標題

不帶頭結點

//函式功能:不帶頭結點隊頭元素出隊
void DeNohead_LinkQueue(LinkQueue *Q,ElemType x){
    if(Q->front==NULL){
        return false;    //空佇列
    }
    LinkNode *p =Q->front;
    //p指向此次出隊的結點
    x=p->data;    
    //用變數x返回隊頭元素
    Q->front=p->next;
    //↑等價於 Q->front=Q->front->next;
    //修改隊頭指
    printf("元素%d已出隊\n",x);
    if(Q->rear==p){  
    //考慮最後一個結點出隊的情況
        Q->rear=NULL;
        Q->front=NULL;
        //修改rear指標
        printf("這是隊中最後一個元素\n");
    }
    free(p);  //釋放結點空間
    return true;
}

定義一個p指向出隊的節點,隊頭走後p指向下一個元素。同時用隊尾是否與p重合來判斷是否是最後一個節點出隊。
與帶頭結點不同的是,新建的節點p直接指向出隊節點,因為沒有頭結點。

返回標題

遍歷

**鏈式佇列的遍歷無論是帶不帶頭結點與普通佇列和迴圈佇列的遍歷是相同框架的,在此僅做對比展示不做分析。

//函式功能:遍歷不帶頭結點的佇列

void traverse_NoHead_LinkQueue(LinkQueue* q) {

    printf("接下來將為您遍歷輸出佇列中的所有元素\n");
    if (q->front == NULL) {
        printf("佇列為空.\n");
        return;
    }
    LinkNode* current = q->front;
    while (current!= NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}
void traverseLinkQueue(LinkQueue* q) {
    printf("接下來將為您遍歷輸出佇列中的所有元素\n");
    if (q->front->next == NULL) {
        printf("佇列為空.\n");
        return;
    }
    LinkNode* current = q->front->next;
    while (current!= NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}
void printCircularQueue(SqQueue*q) {
    if (QueueEmpty(*q)) {
        printf("Queue is empty.\n");
        return;
    }
    int index = q->front;
    while (index!= q->rear) {
        printf("%d ", q->data[index]);
        index = (index + 1) % MaxSize;
    }
    printf("\n");
}

返回標題

全部程式碼展示

返回標題


#include <stdio.h>

#include <stdbool.h>

#include <stdlib.h>

  

//普通佇列和迴圈佇列

typedef int ElemType;

#define MaxSize 10

typedef struct SqQueue{

    ElemType data[MaxSize];  

    //用靜態陣列存放佇列元素

    int front,rear;          

    //定義隊頭指標和隊尾指標

}SqQueue;

//鏈式佇列

typedef struct LinkNode{    

//鏈式佇列結點
    ElemType data;
    struct LinkNode *next;
}LinkNode;  

  

typedef struct LinkQueue{              

//鏈式佇列

    LinkNode *front,*rear;  

    //佇列的隊頭和隊尾指標

}LinkQueue;

  
  
  

//普通佇列和迴圈佇列函式

//函式功能:初始化佇列

void InitQueue(struct SqQueue *Q){

    //初始時,隊頭和隊尾指標都指向0;

    Q->rear=Q->front=0;

    printf("已初始化\n");

}

void testQueue(){

    SqQueue Q;    

    printf("已開空間\n");

    //宣告一個佇列(順序儲存)————這段語句執行後,

    //就會在記憶體中分配連續大小為MaxSize*sizeof(ElemType)的空間

}

//函式功能:判斷佇列是否為空

bool QueueEmpty(SqQueue Q){

    if(Q.rear==Q.front) { //隊空的條件

        printf("隊為空\n");

        return true;}

    else{

        return false;

        printf("隊不為空\n");

        }

}

//函式功能:入隊

/* bool EnQueue(SqQueue* Q,ElemType x){

    /*if(QueueEmpty(*Q)){

        printf("");

        return false;}//報錯

    Q->data[Q->rear]=x;  //將x插入到隊尾

    Q->rear=Q->rear+1;  // 隊尾指標後移

    printf("%d",x);

    return true;

}*/

  

bool  QueueFull(SqQueue* Q){

    if((Q->rear+1)%MaxSize==Q->front)//判斷隊空或滿

        {   printf("隊滿\n");

            return false;}//報錯

        else

        {printf("隊未滿\n");

        return true ;}

  

}

//迴圈佇列入隊

bool EnQueue(SqQueue* Q,ElemType x){

    //if(佇列已滿)

    if((Q->rear+1)%MaxSize==Q->front)//判斷隊空或滿

        return false;//報錯

    Q->data[Q->rear]=x;  //將x插入到隊尾

    Q->rear=(Q->rear+1)%MaxSize;  // 隊尾指標加一取模

    //這個語句的操作,使得Q.rear的取值範圍固定在了{0,1,2,3,...,MaxSize-1}。

    //可以理解將儲存空間變成了“環狀”。

    printf("入隊元素為%d\n",x);

    return true;

}

//迴圈佇列出隊

//函式功能:出隊——刪除一個隊頭元素,並用x返回

bool DeQueue(SqQueue *Q,ElemType x){

    if(Q->rear==Q->front)

        return false;//佇列為空,報錯

    x=Q->data[Q->front];//隊頭元素賦值給x;

    Q->front=((Q->front+1)%MaxSize);

    printf("出隊已完成,出隊元素為%d\n",x);

    //隊頭指標加一取模保證在迴圈佇列中隊頭指標後移;

    return true;

}

//函式功能:獲得隊頭元素的值,用x返回。

bool GetHead(SqQueue *Q,ElemType x){

    if(Q->rear==Q->front){

        printf("隊為空,無法出隊");

        return false;

        }

        else {//隊空,無元素,報錯;

    x=Q->data[Q->front];

    printf("隊頭為%d\n",x);

    return true;}

}

  

bool searchInCircularQueue(SqQueue*q,int target) {

    int index = q->front;
    while (index!= q->rear) {
        if (q->data[index] == target) {
            return true;
        }
        index = (index + 1) % MaxSize;
    }
        return false;
    }
void  FindElement(SqQueue*q,int target){
    if (searchInCircularQueue(q, target)==true) {
        printf("%d 元素在該佇列中.\n", target);
    } else {
        printf("%d 元素不在該佇列中.\n", target);
    }
}
//遍歷輸出
void printCircularQueue(SqQueue*q) {
    if (QueueEmpty(*q)) {
        printf("Queue is empty.\n");
        return;
    }
    int index = q->front;
    while (index!= q->rear) {
        printf("%d ", q->data[index]);
        index = (index + 1) % MaxSize;
    }
    printf("\n");
}
//鏈式佇列

//函式功能:初始化佇列--帶頭結點
void InitLinkQueue (LinkQueue *Q){
    //初始化時,front 和rear指標都指向頭結點
    Q->front=Q->rear
    =(LinkNode*)malloc(sizeof(LinkNode));
    Q->front->next=NULL;
    printf("已初始化一個鏈式佇列\n");
}
//判斷佇列是否為空

bool LinkIsEmpty(LinkQueue *Q){

    if(Q->front==Q->rear)
     //其實,只有為空時,Q.front==Q.rear,其他條件也沒必要考慮了。
        {printf("該鏈式佇列為空\n");
            return true;
        }
    else{
        printf("該鏈式佇列不為空\n");
        return false;
        }
}
//函式功能:帶頭結點佇列新元素入隊--帶頭結點

void EnLinkQueue(LinkQueue *Q,ElemType x){

    LinkNode *newNode =(LinkNode*)malloc(sizeof(LinkNode));//申請一個結點newNode
    newNode->data=x;
    newNode->next=NULL;
    Q->rear->next=newNode;
    //新結點插入到rear之後
    Q->rear=newNode;    
    // 修改表尾指標,入隊操作不需要需要表頭指標front;
    printf("元素%d已入隊\n",x);
}
//函式功能:帶頭結點佇列新元素入隊--帶頭結點

void EnQueueNohead(LinkQueue *Q,ElemType x){
    LinkNode *s =(LinkNode*)malloc(sizeof(LinkNode));
    //申請一個結點s
    s->data=x;
    s->next=NULL;
    if (LinkIsEmpty(Q)) {
        Q->front = Q->rear = s;
    } else {
        Q->rear->next = s;
        //新結點插入到rear之後
        Q->rear = s;
        // 修改表尾指標,
        //入隊操作不需要需要表頭指標front;
    }
}
//函式功能:帶頭結點隊頭元素出隊--帶頭結點

bool DeLinkQueue(LinkQueue *Q,ElemType x){
    if(Q->front->next==NULL){
        printf("空佇列,無法出隊\n");
        return false;  
         //空佇列
    }
    LinkNode *temp =Q->front->next;
    //將頭節點的下一個節點儲存到temp,用於取出數值
    x=temp->data;    
    //用變數x返回隊頭元素
    printf("%d已出隊\n",x);
    Q->front->next=temp->next;
    //修改隊頭指標
    if(Q->rear==temp){  
     //考慮最後一個結點出隊的情況
        Q->rear=Q->front;
        //修改rear指標
        printf("%d已出隊這是隊中最後一個元素\n",x);
    }
    free(temp);
     //釋放結點空間
    return true;
}
//函式功能:遍歷輸出佇列中的所有元素
void traverseLinkQueue(LinkQueue* q) {
    printf("接下來將為您遍歷輸出佇列中的所有元素\n");
    if (q->front->next == NULL) {
        printf("佇列為空.\n");
        return;
    }
    LinkNode* current = q->front->next;
    while (current!= NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}
//鏈式佇列不帶頭結點

//------------------------------

void InitLinkNoHeadQueue (LinkQueue *Q){
     //初始化時,frony 和rear指標都指向NULL
    Q->front = Q->rear = NULL;
    printf("一個不帶頭節點的鏈式佇列已初始化完畢\n");

}
//函式功能:不帶頭結點佇列新元素入隊--帶頭結點
void En_NoHead_Queue(LinkQueue *Q,ElemType x){
    LinkNode *s =(LinkNode*)malloc(sizeof(LinkNode));
    //申請一個結點s
    s->data=x;
    s->next=NULL;
    if (Q->rear==NULL) {
        Q->front = Q->rear = s;
        printf("元素%d已入隊\n",x);
    } else {
        Q->rear->next = s;
        //新結點插入到rear之後
        Q->rear = s;
        printf("元素%d已入隊\n",x);
        // 修改表尾指標,
        //入隊操作不需要需要表頭指標front;
    }
}
//函式功能:不帶頭結點隊頭元素出隊

bool DeNohead_LinkQueue(LinkQueue *Q,ElemType x){
    if(Q->front==NULL){
        return false;    //空佇列
    }
    LinkNode *p =Q->front;
    //p指向此次出隊的結點
    x=p->data;    
    //用變數x返回隊頭元素
    Q->front=p->next;
    //↑等價於 Q->front=Q->front->next;
    //修改隊頭指標
    printf("元素%d已出隊\n",x);
    if(Q->rear==p){  
    //考慮最後一個結點出隊的情況
        Q->rear=NULL;
        Q->front=NULL;
        //修改rear指標
        printf("這是隊中最後一個元素\n");
    }
    free(p);  //釋放結點空間
    return true;
}
//函式功能:遍歷不帶頭結點的佇列
void traverse_NoHead_LinkQueue(LinkQueue* q) {
    printf("接下來將為您遍歷輸出佇列中的所有元素\n");
    if (q->front == NULL) {
        printf("佇列為空.\n");
        return;
    }
    LinkNode* current = q->front;
    while (current!= NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}
void main(){
    int x;
    LinkQueue Q;    //宣告一個鏈式佇列
    //帶頭結點
    InitLinkQueue(&Q);
    LinkIsEmpty(&Q);
    EnLinkQueue(&Q,1);
    EnLinkQueue(&Q,2);
    DeLinkQueue(&Q,x);
    EnLinkQueue(&Q,1);
    EnLinkQueue(&Q,2);
    traverseLinkQueue(&Q);
    //不帶頭結點
     InitLinkNoHeadQueue(&Q);
    En_NoHead_Queue(&Q,2);
    DeNohead_LinkQueue(&Q,x);
    En_NoHead_Queue(&Q,2);
    En_NoHead_Queue(&Q,2);
    traverse_NoHead_LinkQueue(&Q);
    En_NoHead_Queue(&Q,2);
}
//普通佇列和迴圈佇列函式呼叫
    /*SqQueue q;
    InitQueue(&q);
    QueueEmpty(q);
    QueueFull(&q);
    EnQueue( &q,1);
    EnQueue( &q,5);
    DeQueue(&q, x);
    GetHead(&q,x);
    EnQueue( &q,2);
    EnQueue( &q,4);
    EnQueue( &q,1);
    printCircularQueue(&q);
    //earchInCircularQueue(&q,4);
    FindElement(&q,1);*/
//--------

返回標題

相關文章