【基础数据结构】队列

 队列FIFO

#include
#include // 添加此头文件以使用 malloc 和 free 函数

typedef int DataType;

// 定义队列结点结构体
struct QueueNode {
	DataType data; // 数据
	struct QueueNode* next; // 指向下一个结点的指针
};

// 定义队列结构体
struct Queue {
	struct QueueNode* head; // 队列头指针
	struct QueueNode* tail; // 队列尾指针
	int size; // 队列大小
};

// 入队操作
void QueueEnqueue(struct Queue* que, DataType dt) {
	// 创建新结点
	struct QueueNode* vtx = (struct QueueNode*)malloc(sizeof(struct QueueNode));
	vtx->data = dt;
	vtx->next = NULL;

	// 将新结点添加到队列尾部
	if (que->tail) {
		que->tail->next = vtx;
	} else {
		que->head = vtx;
	}
	que->tail = vtx;

	++que->size;
}

// 出队操作
void QueueDequeue(struct Queue* que) {
	// 保存队列头结点的指针
	struct QueueNode* temp = que->head;

	// 更新队列头指针
	que->head = temp->next;
	free(temp); // 释放原头结点的内存

	--que->size;

	// 如果队列为空,更新队列尾指针
	if (que->size == 0) {
		que->tail = NULL;
	}
}

// 获取队列头结点的数据
DataType QueueGetFront(struct Queue* que) {
	return que->head->data;
}

int main() {
	// 创建一个队列
	struct Queue queue;
	queue.head = NULL;
	queue.tail = NULL;
	queue.size = 0;

	// 入队操作
	QueueEnqueue(&queue, 10);
	QueueEnqueue(&queue, 20);
	QueueEnqueue(&queue, 30);

	// 打印队列头结点的数据
	printf("Front element: %d\n", QueueGetFront(&queue));

	// 出队操作
	QueueDequeue(&queue);

	// 打印队列头结点的数据
	printf("Front element: %d\n", QueueGetFront(&queue));

	return 0;
}

例题1

动物收容所

动物收容所。有家动物收容所只收容狗与猫,且严格遵守“先进先出”的原则。在收养该收容所的动物时,收养人只能收养所有动物中“最老”(由其进入收容所的时间长短而定)的动物,或者可以挑选猫或狗(同时必须收养此类动物中“最老”的)。换言之,收养人不能自由挑选想收养的对象。请创建适用于这个系统的数据结构,实现各种操作方法,比如enqueuedequeueAnydequeueDogdequeueCat。允许使用Java内置的LinkedList数据结构。

enqueue方法有一个animal参数,animal[0]代表动物编号,animal[1]代表动物种类,其中 0 代表猫,1 代表狗。

dequeue*方法返回一个列表[动物编号, 动物种类],若没有可以收养的动物,则返回[-1,-1]

示例1:

 输入:
["AnimalShelf", "enqueue", "enqueue", "dequeueCat", "dequeueDog", "dequeueAny"]
[[], [[0, 0]], [[1, 0]], [], [], []]
 输出:
[null,null,null,[0,0],[-1,-1],[1,0]]

示例2:

 输入:
["AnimalShelf", "enqueue", "enqueue", "enqueue", "dequeueDog", "dequeueCat", "dequeueAny"]
[[], [[0, 0]], [[1, 0]], [[2, 1]], [], [], []]
 输出:
[null,null,null,null,[2,1],[0,0],[1,0]]

说明:

  1. 收纳所的最大容量为20000
#include 
#include 

typedef struct {
    int animalNum;
    int animalType;
} Animal;

typedef struct Node {
    Animal animal;
    struct Node* next;
} Node;

typedef struct {
    Node* front;
    Node* rear;
} Queue;
typedef struct {
    Queue* catQueue;
    Queue* dogQueue;
} AnimalShelter;
Queue* createQueue() {
    Queue* queue = (Queue*)malloc(sizeof(Queue));
    queue->front = NULL;
    queue->rear = NULL;
    return queue;
}

int isEmpty(Queue* queue) {
    return (queue->front == NULL);
}

void enqueue(Queue* queue, Animal animal) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->animal = animal;
    newNode->next = NULL;

    if (isEmpty(queue)) {
        queue->front = newNode;
        queue->rear = newNode;
    } else {
        queue->rear->next = newNode;
        queue->rear = newNode;
    }
}

Animal dequeue(Queue* queue) {
    if (isEmpty(queue)) {
        Animal emptyAnimal = {-1, -1};
        return emptyAnimal;
    }

    Node* temp = queue->front;
    Animal animal = temp->animal;
    queue->front = queue->front->next;

    if (queue->front == NULL) {
        queue->rear = NULL;
    }

    free(temp);
    return animal;
}

AnimalShelter* animalShelterCreate() {
    AnimalShelter* shelter = (AnimalShelter*)malloc(sizeof(AnimalShelter));
    shelter->catQueue = createQueue();
    shelter->dogQueue = createQueue();
    return shelter;
}

void animalShelterEnqueue(AnimalShelter* shelter, Animal animal) {
    if (animal.animalType == 0) { // Cat
        enqueue(shelter->catQueue, animal);
    } else if (animal.animalType == 1) { // Dog
        enqueue(shelter->dogQueue, animal);
    }
}

// 出队任意类型的最早进入收容所的动物
Animal animalShelterDequeueAny(AnimalShelter* shelter) {
    if (!isEmpty(shelter->catQueue) && !isEmpty(shelter->dogQueue)) {
        // 如果收容所中既有猫又有狗,比较它们的进入时间,选择较早进入的动物类型
        Node* catFront = shelter->catQueue->front;
        Node* dogFront = shelter->dogQueue->front;
        if (catFront->animal.animalNum < dogFront->animal.animalNum) {
            return dequeue(shelter->catQueue);
        } else {
            return dequeue(shelter->dogQueue);
        }
    } else if (!isEmpty(shelter->catQueue)) {
        // 如果只有猫,出队最早进入收容所的猫
        return dequeue(shelter->catQueue);
    } else if (!isEmpty(shelter->dogQueue)) {
        // 如果只有狗,出队最早进入收容所的狗
        return dequeue(shelter->dogQueue);
    } else {
        // 如果收容所为空,返回一个空的Animal结构体表示没有动物可出队
        Animal emptyAnimal = {-1, -1};
        return emptyAnimal;
    }
}
Animal animalShelterDequeueCat(AnimalShelter* shelter) {
    return dequeue(shelter->catQueue);
}

Animal animalShelterDequeueDog(AnimalShelter* shelter) {
    return dequeue(shelter->dogQueue);
}

int main() {
    AnimalShelter* shelter = animalShelterCreate();

    Animal animal1 = {0, 0}; // Cat
    Animal animal2 = {1, 0}; // Cat
    Animal animal3 = {2, 1}; // Dog

    animalShelterEnqueue(shelter, animal1);
    animalShelterEnqueue(shelter, animal2);
    animalShelterEnqueue(shelter, animal3);

    // Dequeue the oldest animal of any type
    Animal oldestAnimal1 = animalShelterDequeueAny(shelter);
    printf("Dequeued animal: animalNum = %d, animalType = %d\n", oldestAnimal1.animalNum, oldestAnimal1.animalType);

    // Dequeue the oldest cat
    Animal oldestCat = animalShelterDequeueCat(shelter);
    printf("Dequeued cat: animalNum = %d, animalType = %d\n", oldestCat.animalNum, oldestCat.animalType);

    // Dequeue the oldest dog
    Animal oldestDog = animalShelterDequeueDog(shelter);
    printf("Dequeued dog: animalNum = %d, animalType = %d\n", oldestDog.animalNum, oldestDog.animalType);

    return 0;
}

 例题2

最近的请求次数

写一个 RecentCounter 类来计算特定时间范围内最近的请求。

请你实现 RecentCounter 类:

  • RecentCounter() 初始化计数器,请求数为 0 。
  • int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。

保证 每次对 ping 的调用都使用比之前更大的 t 值。

示例 1:

输入:
["RecentCounter", "ping", "ping", "ping", "ping"]
[[], [1], [100], [3001], [3002]]
输出:
[null, 1, 2, 3, 3]

解释:
RecentCounter recentCounter = new RecentCounter();
recentCounter.ping(1);     // requests = [1],范围是 [-2999,1],返回 1
recentCounter.ping(100);   // requests = [1, 100],范围是 [-2900,100],返回 2
recentCounter.ping(3001);  // requests = [1, 100, 3001],范围是 [1,3001],返回 3
recentCounter.ping(3002);  // requests = [1, 100, 3001, 3002],范围是 [2,3002],返回 3

提示:

  • 1 <= t <= 109
  • 保证每次对 ping 调用所使用的 t 值都 严格递增
  • 至多调用 ping 方法 104 次
#include 

#define MAX_SIZE 3002

typedef struct {
    int queue[MAX_SIZE];
    int front;
    int rear;
} RecentCounter;

// 初始化计数器
RecentCounter* recentCounterCreate() {
    RecentCounter* counter = (RecentCounter*)malloc(sizeof(RecentCounter));
    counter->front = 0;
    counter->rear = -1;
    return counter;
}

// 添加新请求并返回过去3000毫秒内的请求数
int ping(RecentCounter* counter, int t) {
    counter->rear = (counter->rear + 1) % MAX_SIZE;
    counter->queue[counter->rear] = t;

    int startTime = t - 3000;
    int count = 0;
    int i = counter->front;

    while (counter->queue[i] < startTime) {
        i = (i + 1) % MAX_SIZE;
    }

    while (i != (counter->rear + 1) % MAX_SIZE) {
        count++;
        i = (i + 1) % MAX_SIZE;
    }

    return count;
}

int main() {
    RecentCounter* counter = recentCounterCreate();
    printf("%d\n", ping(counter, 1));    // requests = [1],范围是 [-2999,1],返回 1
    printf("%d\n", ping(counter, 100));  // requests = [1, 100],范围是 [-2900,100],返回 2
    printf("%d\n", ping(counter, 3001)); // requests = [1, 100, 3001],范围是 [1,3001],返回 3
    printf("%d\n", ping(counter, 3002)); // requests = [1, 100, 3001, 3002],范围是 [2,3002],返回 3

    return 0;
}

例题3

滑动窗口最大值

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length
#include 
#include 

int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
    int q[numsSize]; // 双端队列,用于保存窗口中的元素索引
    int left = 0, right = 0; // 队列的头部和尾部索引
    int i = 0;

    // 遍历窗口中的前 k 个元素
    for (i = 0; i < k; ++i) {
        // 维护队列的性质:保持队列中的元素按照从大到小的顺序排列
        while (left < right && nums[i] >= nums[q[right - 1]]) {
            right--;
        }
        q[right++] = i; // 将当前元素索引加入队列
    }

    *returnSize = 0;
    int* ans = malloc(sizeof(int) * (numsSize - k + 1)); // 分配存储结果的数组
    ans[(*returnSize)++] = nums[q[left]]; // 将窗口中的最大值加入结果数组

    int j = 0;
    // 遍历窗口中的剩余元素
    for (j = k; j < numsSize; ++j) {
        // 维护队列的性质:保持队列中的元素按照从大到小的顺序排列
        while (left < right && nums[j] >= nums[q[right - 1]]) {
            right--;
        }
        q[right++] = j; // 将当前元素索引加入队列

        // 检查队列头部的元素是否仍在窗口内,如果不在则移除
        while (q[left] <= j - k) {
            left++;
        }
        ans[(*returnSize)++] = nums[q[left]]; // 将窗口中的最大值加入结果数组
    }

    return ans;
}

int main() {
    int nums[] = {1, 3, -1, -3, 5, 3, 6, 7};
    int k = 3;
    int numsSize = sizeof(nums) / sizeof(nums[0]);
    int returnSize;
    int* result = maxSlidingWindow(nums, numsSize, k, &returnSize);
    int i = 0;
    for (i = 0; i < returnSize; i++) {
        printf("%d ", result[i]);
    }
    printf("\n");

    free(result);

    return 0;
}

你可能感兴趣的:(基础数据结构,数据结构)