队列ADT--链表实现与数组实现

        像栈一样,队列(queue)也是表。然而,使用队列时插入在一端进行而删除则在另一端进行。

        队列模型

        队列的基本操作是 Enqueue(入队)-- 在表的末端(叫作队尾(rear))插入一个元素,还有Dequeue(出队)-- 删除(或返回)在表的开头(叫作队头(front))的元素。

        队列的链表实现

        对于链表实现队列,我们要使用循环链表,这是为了保证每个操作都是O(1)运行时间。否则入队需要O(N)时间。

        类型声明:

typedef struct Node* PtrToNode;
typedef PtrToNode Queue;
typedef int ElementType;

struct Node
{
	ElementType element;
	PtrToNode prev;
	PtrToNode next;
};

        表头创建:

Queue QueueCreate()
{
	Queue q = (Queue)malloc(sizeof(struct Node));
	if (q != NULL)
	{
		q->element = 0;
		q->prev = q;
		q->next = q;
	}
	return q;
}

        入队与出队:

void Enqueue(Queue q, ElementType x)
{
	PtrToNode tmpNode = (PtrToNode)malloc(sizeof(struct Node));
	PtrToNode lastNode = q->prev;
	if (tmpNode == NULL)
	{
		printf("error in creating node\n");
		return;
	}
	tmpNode->element = x;
	lastNode->next = tmpNode;
	tmpNode->prev = lastNode;
	tmpNode->next = q;
	q->prev = tmpNode;
}
void Dequeue(Queue q)
{
	if (IsEmpty(q))
	{
		printf("queue is already empty");
		return;
	}
	PtrToNode tmpNode = q->next;
	q->next = tmpNode->next;
	free(tmpNode);
}

        是否为空、置空与释放:

int IsEmpty(Queue q)
{
	return q->next == q;
}
void MakeEmpty(Queue q)
{
	while (!IsEmpty(q))
	{
		Dequeue(q);
	}
}
void DisposeQueue(Queue q)
{
	MakeEmpty(q);
	free(q);
}

        返回队头和返回队头并出队,同样这里用 int 最大值表示无队头,当然直接报错是更好的。

ElementType Front(Queue q)
{
	if (!IsEmpty(q))
	{
		return q->next->element;
	}
	return INT_MAX;
}
ElementType FrontAndDequeue(Queue q)
{
	ElementType tmp;
	if (!IsEmpty(q))
	{
		tmp = q->next->element;
		Dequeue(q);
		return tmp;
	}
	return INT_MAX;
}

         队列的数组实现

        对于每一个队列数据结构,我们保留一个数组 Queue[] 以及 位置 front 和 rear,它们代表队列的两端。我们还要记录实际存在于队列中的元素的个数 size

        操作应该是很清楚地,为了使一个元素 x 入队,我们让 rear 和 size 增1,然后置 Queue[rear] = x。 若使一个元素出队,我们置返回值为 Queue[front],front 增1 然后使 size 减1。

        这种实现存在一个潜在的问题,若实现队列的数组大小为10,则经过10次入队时队列就满了,rear就变成了10,再经过出队,可以让前面的元素出队腾出空间,现在我们再想要入队就会发现rear此时的位置不在队列之中。像栈一样,即使在有许多操作的情况下队列也常常不是很大。所以这种情况会经常发生。

        简单的解决方法就是,只要 front 或 rear 到达数组的尾端,它就又绕回到开头。这叫作循环数组实现。

        关于队列的循环实现,有两件事情要警惕

        第一,检测队列是否为空是很重要的,因为当队列为空时,一次Dequeue操作将会不知不觉返回一个不确定的值。

         第二,某些设计人员使用不同方法来表示队列的队头和队尾。例如有些并不用一个单元来表示队列大小,因为他们依靠的是基准情形,当 front = rear + 1时,队列为空。队列的大小通过front和rear隐式算出,例如rear-front = 2,表示有三个元素。如果队列大小不是结构的一部分,这样的话写代码就需要特别仔细,如果数组大小为10,则当存在9个元素时队列就满了。比如一开始为空队列则 rear = 0,front = 1。先入队9个元素,rear = 9 ,此时存了9个元素应该就算满了,如果我们允许存储10个元素的话,那么再入队一个元素,rear = 0,此时发现 rear = 0,front = 1 又表示十个元素存在,那么这种情况到底是表示有十个元素呢还是表示队列为空呢,为了不出现这种分歧,我们就只存9个元素,这种情况下则始终表示空队列,所以实际上这种方法队列的最大元素数量为实现队列的数组大小减1。但是如果我们使用size表示大小,当出现 rear 为 9,front 为 0 的情况时,我们就能直接知道,当size=0时表示空队列,当size=10时表示队列有十个元素。由此来看如果不用size字段,就有必要在代码中插入一些注释。

        类型声明

#define MinQueueSize (5)
typedef int ElementType;
typedef struct QueueRecord* Queue;

struct QueueRecord
{
	ElementType* array;
	int size;
	int front;
	int rear;
	int capacity;
};

        队列创建:

Queue QueueCreate(int maxElements)
{
	Queue q = (Queue)malloc(sizeof(struct QueueRecord));
	int realSize = maxElements > MinQueueSize ? maxElements : MinQueueSize;
	if (q != NULL)
	{
		q->front = 1;
		q->rear = 0;
		q->size = 0;
		q->capacity = realSize;
		q->array = (ElementType*)malloc(realSize * sizeof(ElementType));
		if (q->array == NULL)
		{
			free(q);
			return NULL;
		}
	}
	return q;
}

        入队和出队:

void Enqueue(Queue q, ElementType x)
{
	if (IsFull(q))
	{
		printf("queue is already full\n");
		return;
	}
	q->rear++;
	if (q->rear == q->capacity)
		q->rear = 0;
	q->array[q->rear] = x;
	q->size++;
}
void Dequeue(Queue q)
{
	if (IsEmpty(q))
	{
		printf("queue is already empty\n");
		return;
	}
	q->front++;
	if (q->front == q->capacity)
		q->front = 0;
	q->size--;
}

        判断队列为空和队列满:

int IsEmpty(Queue q)
{
	return q->size == 0;
}
int IsFull(Queue q)
{
	return q->size == q->capacity;
}

        置空队列和释放队列

void MakeEmpty(Queue q)
{
	q->front = 1;
	q->rear = 0;
	q->size = 0;
}
void DisposeQueue(Queue q)
{
	free(q->array);
	free(q);
}

        返回队头

ElementType Front(Queue q)
{
	if (IsEmpty(q))
		return INT_MAX;
	return q->array[q->front];
}

        打印队列

void PrintQueue(Queue q)
{
	int i = 0;
	int size = q->size;
	for (i = q->front; size > 0; size--, i++)
	{
		printf("%d ", q->array[i]);
	}
}

如此队列就实现了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值