【数据结构】双端队列

定义

deque(double-ended queue,双端队列)是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出。

结构示意图

首先每个节点包含一个存储的元素和一个指向下一节点的指针。整个双端队列则只包含一个头(head)节点的指针和一个尾(tail)节点的指针。头节点指向链表的第一个元素,尾节点指向最后一个元素。
请添加图片描述定义的代码

struct Node{
	T elem;
	struct Node * next;
};
typedef struct Deque{
	struct Node * head;
	struct Node * tail;
}Deque;

需要实现的操作有:

头插(pushFront)、尾插(pushBack)、头出(popFront)、尾出(popBack)、获取头元素(peekFront)、获取尾元素(peekBack)、初始化、是否为空、获取大小、清空。

实现

这是初始化、是否为空、获取大小、清空的代码。简单说下。

初始化:头尾都置为NULL

是否为空:返回是否头部为空

获取大小:从头部开始遍历直到为空,记录size

清空:定义一个node和next节点,node用于记录当前即将删除的节点,next为下一个节点。每次循环需要先指定next节点再释放node。最后将队列que的head和tail置为空。

int initDeque(Deque * que){
	assert(que != NULL);
	que->head = NULL;
	que->tail = NULL;
	return SUCCESS;
}
bool emptyQueue(Deque * que){
	assert(que != NULL);
	return que->head != NULL;
}
size_t sizeQueue(Deque * que){
	assert(que != NULL);
	size_t size =0;
	struct Node * node = que->head;
	while(node != NULL){
		++size;
		node=node->next;

	}
	return size;
}
void clearQueue(Deque * que){
	assert(que != NULL);
	struct Node *node,*next;
	for(que->head; node != NULL; node=next){
		next=node->next;
		free(node);

	}
	que->head=que->tail=NULL;
}

创建节点,插入需要用到的一个静态函数。传入节点的元素和下一个节点地址。先定义一个节点,初始化为动态申请内存,再将elem和next都赋予相应的对象。

static struct Node * createNode(T elem,struct Node *next){
	struct Node *node=(struct Node *) malloc(sizeof(struct Node));
	if(node!=NULL){
		node->elem=elem;
		node->next=next;
	}
	return node;
}

头插,先创建节点(注意传参的next要指定为que->head),再用此节点取代头节点。如果tail为空(代表此前que为空),也要使这个节点充当tail(因为现在只有这一个元素。)

int pushFrontQueue(Deque * que,T elem){
	assert(que != NULL);
	struct Node *node = createNode(elem,que->head);
	if(node==NULL){
		return FAILURE;
	}
	que->head=node;
	if(que->tail==NULL){
		que->tail=node;
	}
	return SUCCESS;
}

尾插,先创建一个节点,传参的next为空(在尾部插入,后面没有其他节点)。当tail不为空,将此节点设置为tail的next,当节点为空,此节点先取代head(que为空,需要兼任head),最后,取代tail(因为插入到尾部后此节点就成了新的尾部。)

int pushBackQueue(Deque *que,T elem)
{
	assert(que!=NULL);
	struct Node *node = createNode(elem,NULL);
	if(node==NULL){
		return FAILURE;
	}
	if(que->tail!=NULL){
		que->tail->next=node;
	}
	else{
		que->head=node;
	}
	que->tail=node;
	return SUCCESS;
}

获取头节点,当head不为空,把head的elem赋值给*pelem。

int peekFirstQueue(Deque * que, T *pelem){
	assert(que != NULL);
	if(que->head==NULL){
		return FAILURE;
	}
	if(pelem!= NULL){
		*pelem=que->head->elem;
	}
	return SUCCESS;

}

获取尾节点,类似的道理,解释略。

int peekLastQueue(Deque * que, T *pelem){
	assert(que != NULL);
	if(que->tail==NULL){
		return FAILURE;
	}
	if(pelem!=NULL){
		*pelem=que->tail->elem;
	}
	
	return SUCCESS;
}

弹出头结点,可以用一个元素地址接受被弹出的元素。先判断que是否为空,是的话就不能弹出。记录head->next,释放head,再用记录的节点取代head。判断head是否为NULL(弹出后que是否为空),如果是,要把tail置为NULL。

int popFrontQueue(Deque * que,T* pelem){
	assert(que!=NULL);
	if(que->head==NULL){
		return FAILURE;
	}
	if(pelem!=NULL){
		*pelem=que->head->elem;
	}
	struct Node* node =que->head->next;
	free(que->head);
	que->head=node;
	if(que->head==NUL){
		que->tail=NULL;
	}
	return SUCCESS;
} 
} 

弹出尾节点,可以用一个元素地址去接受弹出的元素。先判断que是否为空,是的话就不能弹出。判断head等于tail的情况(只有一个节点),释放head,再将head和tail同时置NULL。当节点多于一个,就先用一个while循环找到tail的前一个节点,释放tail,将tail前一个节点作为tail。

int popBackQueue(Deque * que,T * pelem){
	assert(que != NULL);
	if(que->tail==NULL){
		return FAILURE;
	}
	if(pelem!=NULL){
		*pelem=que->tail->elem;
	}
	if(que->head==que->tail){
		free(que->head);
		que->head=que->tail=NULL;
	}
	else{
		struct Node *node=que->head;
		while(node->next!=que->tail){
			node=node->next;
		}
		node->next=NULL;
		free(que->tail);
		que->tail=node;
	}
	return SUCCESS;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值