动态

详情 返回 返回

C語言實現循環隊列——始化、入隊、出隊與完整測試 - 动态 详情

隊列的基本操作實現

1.隊列的概念

🌟 隊列(Queue)—— 先進先出的數據結構

隊列是一種線性數據結構,遵循 “先進先出”(FIFO, First In First Out) 的原則。如現實中的排隊:先來的人先被服務,後來的人排在隊尾等待。

🔧 基本操作:

  • 入隊(Enqueue):在隊尾添加一個新元素。
  • 出隊(Dequeue):從隊頭移除一個元素。
  • 查看隊頭(Front):獲取隊頭元素,但不移除。
  • 判空(IsEmpty):判斷隊列是否為空。
  • 獲取大小(Size):返回隊列中元素個數。

📦 存儲方式:

隊列可以用兩種主要方式實現:

  1. 順序存儲:使用數組實現,可優化為循環隊列以避免空間浪費。
  2. 鏈式存儲:使用鏈表實現,動態分配內存,靈活性高。

2.鏈式存儲--代碼實現

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

typedef int DataType_t;

// 鏈表節點結構體(改為 QueueNode)
typedef struct QueueNode {
    DataType_t data;
    struct QueueNode* next;
} QueueNode;

// 隊列的結構體(改為 LinkedQueue,表示鏈式隊列)
typedef struct {
    QueueNode* rear;   // 指向隊尾節點
    int size;
} LinkedQueue;

// 為 LinkedQueue* 定義別名 Queue,表示一個隊列的指針
typedef LinkedQueue* Queue;

/**
 * 初始化隊列
 * @param q 指向隊列指針的指針(二級指針),用於返回隊列的地址
 * @return 成功返回 1,失敗返回 0
 */
int InitQueue(Queue* q)
{
    if (q == NULL) return 0;
    // 申請內存存儲管理隊列的結構體
    *q = (Queue)malloc(sizeof(LinkedQueue));
    if (*q == NULL) return 0;

    (*q)->size = 0;
    (*q)->rear = NULL;
    return 1;   
}

/**
 * 入隊操作:一個新元素入隊列
 * @param q 隊列指針
 * @param data 要入隊列的數據
 * @return 成功返回 1,失敗返回 0
 */
int EnQueue(Queue q, DataType_t data)
{
    if (q == NULL) return 0;
    QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
    if (newNode == NULL) return 0;

    newNode->data = data;
    // 如果隊列空
    if (q->rear == NULL) {
        newNode->next = newNode;
        q->rear = newNode;
    } else {//新節點放到尾節點之後,再更新rear指向
        newNode->next = q->rear->next;
        q->rear->next = newNode;
        q->rear = newNode;
    }

    q->size++;
    return 1;
}

// 判斷隊列是否空
bool IsEmpty(Queue q) {
    return q == NULL || q->rear == NULL;
}

// 計算隊列元素個數
int GetSize(Queue q) {
    if (q == NULL) return -1;
    return q->size;
}

/**
 * 出隊操作:
 * @param q 隊列指針
 * @param data 存儲出隊元素的值 
 * @return 成功返回 1,失敗返回 0
 */
int DeQueue(Queue q, DataType_t* data) {
    if (q == NULL || q->rear == NULL) {
        return 0; // 空隊列或無效隊列
    }

    QueueNode* frontNode = q->rear->next; // 隊頭是 rear->next
    *data = frontNode->data;

    if (q->rear == frontNode) {
        // 只有一個節點
        free(frontNode);
        q->rear = NULL;
    } else {
        // 多個節點
        q->rear->next = frontNode->next; // 跳過隊頭
        free(frontNode);
    }

    q->size--;
    return 1;
}

void DestroyQueue(Queue* q) {
    if (q == NULL || *q == NULL) return;

    if ((*q)->rear != NULL) {
        QueueNode* current = (*q)->rear->next; // 隊頭
        QueueNode* head = current;
        QueueNode* temp;

        do {
            temp = current;
            current = current->next;
            free(temp);
        } while (current != head);
    }

    free(*q);
    *q = NULL;
}

void PrintQueue(Queue q) {
    if (IsEmpty(q)) {
        printf("Queue is empty.\n");
        return;
    }

    QueueNode* current = q->rear->next; // 從隊頭開始
    printf("Queue (front -> rear): ");
    do {
        printf("%d ", current->data);
        current = current->next;
    } while (current != q->rear->next);
    printf("\n");
}

int main() {
    Queue myQueue;
    
    if (!InitQueue(&myQueue)) {
        printf("Failed to initialize queue.\n");
        return -1;
    }

    printf("EnQueue: 10, 20, 30\n");
    EnQueue(myQueue, 10);
    EnQueue(myQueue, 20);
    EnQueue(myQueue, 30);
    PrintQueue(myQueue);
    printf("Size: %d\n", GetSize(myQueue));

    DataType_t val;
    printf("DeQueue: ");
    while (DeQueue(myQueue, &val)) {
        printf("%d ", val);
        if (IsEmpty(myQueue)) break;
    }
    printf("\n");

    printf("After dequeue all: empty? %s\n", IsEmpty(myQueue) ? "yes" : "no");

    DestroyQueue(&myQueue);
    return 0;
}

運行結果

vmware_n7Z9gduu87


順序存儲--(循環隊列)代碼實現

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


// 定義隊列中元素的數據類型為 int
typedef int DataType_t; 

// 循環隊列結構體定義
typedef struct CircularQueue 
{
	DataType_t   *Addr;		// 指向動態分配的數組,用於存儲數據
	int  	      Rear;		// 隊尾索引(指向下一個插入位置)
	int 		 Front;		// 隊頭索引(指向當前第一個元素)
	unsigned int  Size;		// 隊列總容量(數組大小)
}CircQueue_t;

/**
 * 初始化循環隊列
 * @param size 隊列的最大容量
 * @return 成功返回隊列指針,失敗則退出程序
 */
CircQueue_t* CircQueue_init(unsigned int size)
{
	CircQueue_t *Manager = (CircQueue_t*)calloc(1,sizeof(CircQueue_t));

	if(Manager == NULL){
		perror("calloc for Manager is failed!\n");
		exit(-1);
	}

	// 為數據數組分配內存
	Manager->Addr = (DataType_t *)calloc(size,sizeof(DataType_t));
	if(Manager->Addr == NULL){
		perror("calloc for Eelement is failed\n");
		free(Manager);
		exit(-1);
	}
	Manager->Size = size;	// 設置容量
	Manager->Rear = 0;		// 初始隊尾為0
	Manager->Front = 0; 	// 初始隊頭為0
	return Manager; 		// 返回初始化後的隊列
}

/**
 * 判斷隊列是否已滿
 * @param Manager 隊列指針
 * @return 滿則返回 true,否則返回 false
 */
bool CircQueueIsfull(CircQueue_t *Manager)
{
	// 當 (Rear+1) % Size == Front 時,隊滿(犧牲一個空間,用空間換時間)
	return ((Manager->Rear+1)%Manager->Size == Manager->Front)?true:false;

}

/**
 * 判斷隊列是否為空
 * @param Manager 隊列指針
 * @return 空則返回 true,否則返回 false
 */
bool CircQueueIsEmpty(CircQueue_t *Manager)
{
	 // Front == Rear 表示隊列為空
	return ( Manager->Front == Manager->Rear)?true:false;
}

/**
 * 入隊操作
 * @param Manager 隊列指針
 * @param data 要入隊的數據
 * @return 成功返回 true,失敗(隊滿)返回 false
 */
bool CircQueue_Push(CircQueue_t *Manager,DataType_t data)
{	
	
	if(CircQueueIsfull(Manager)){
		printf("Full!\n");
		return false;
	}

	Manager->Addr[Manager->Rear] = data;				// 數據放入隊尾;
	Manager->Rear = (Manager->Rear+1)%Manager->Size;	// rear 向後移動,循環

	return true;
}

/**
 * 出隊操作
 * @param Manager 隊列指針
 * @param data 用於保存出隊的數據(通過指針返回)
 * @return 成功返回 true,失敗(隊空)返回 false
 */
bool CircQueue_Pop(CircQueue_t* Manager, DataType_t* data)
{
    // 檢查隊列是否為空
    if (CircQueueIsEmpty(Manager)) {
        printf("Empty!\n");
        return false;  // 出隊失敗
    }

    // 取出隊頭元素
    *data = Manager->Addr[Manager->Front];
    // 移動隊頭指針:向後移動一位,模 Size 實現循環
    Manager->Front = (Manager->Front + 1) % Manager->Size;

    return true;  // 出隊成功
}

int main(int argc, char const *argv[])
{
    // 初始化一個大小為 3 的循環隊列
    CircQueue_t* q = CircQueue_init(3);

    DataType_t val;

    // --- 測試入隊 ---
    printf("=== 入隊測試 ===\n");
    if (CircQueue_Push(q, 10)) {
        printf("成功入隊: 10\n");
    }
    if (CircQueue_Push(q, 20)) {
        printf("成功入隊: 20\n");
    }
    if (CircQueue_Push(q, 30)) {
        printf("成功入隊: 30\n");
    }
    if (CircQueue_Push(q, 40)) {
        printf("成功入隊: 40\n");
    } else {
        printf("入隊 40 失敗:循環隊列隊列已滿!\n");
    }

    // --- 測試出隊 ---
    printf("\n=== 出隊測試 ===\n");
    if (CircQueue_Pop(q, &val)) {
        printf("成功出隊: %d\n", val);
    }
    if (CircQueue_Pop(q, &val)) {
        printf("成功出隊: %d\n", val);
    }

    // --- 測試循環入隊 ---
    printf("\n=== 測試循環特性 ===\n");
    if (CircQueue_Push(q, 40)) {
        printf("成功入隊: 40\n");
    }
    if (CircQueue_Push(q, 50)) {
        printf("成功入隊: 50\n");
    } else {
        printf("入隊 50 失敗:循環隊列隊列已滿!\n");
    }

    // --- 出隊剩餘元素 ---
    printf("\n=== 清空隊列 ===\n");
    while (CircQueue_Pop(q, &val)) {
        printf("成功出隊: %d\n", val);
    }
    printf("隊列已空,測試結束。\n");

    // --- 釋放資源 ---
    free(q->Addr);  // 釋放數據數組
    free(q);        // 釋放隊列結構體

    return 0;
}

運行結果

vmware_P0y7jG83fi

user avatar EricsT 头像 nuanshu 头像
点赞 2 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.