typedef struct node{
int data;
struct node *next;
}*list,lnode;
约定:附加头结点的data用于储存队列中有几个节点(不包括附加头结点),另设尾指针rear,指向队列的最后一个节点,当队列为空时,rear指向附加头结点,rear->next = rear;当队列不为空时,rear所指节点的下一个是附加头结点,附加头结点的下一个才是队列的真正的头结点。
由于使用了附加头结点的data统计队列的长度,因此把求队列长度这一操作的时间复杂度从O(n)降到了O(1),在统计时候,只需要返回rear->next->data;即可
插入操作:
void insert(list &sq,int x){
list new = (list)malloc(sizeof(lnode));
new->data = x;
new->next = rear->next;//把附加头结点先记在新节点中
rear->next = new;//把新节点加入到队列尾部
rear = new;//尾指针指向新的尾结点
rear->next->data ++;//这一步很容易忘
}
判空,求长度,打印等比较简单,在这里就不再赘述
唯一有点小小问题的点在于删除操作,这里有个小坑
bool del(list &sq,int &item){//假设要把删除节点的值通过item返回
if(rear->next->data == 0){//删除操作嘛,肯定要先看看队列是不是空的
printf("error");
return false;
}
else{
list exhead = rear->next;//附加头结点
list head = rear->next->next;//真正队列中的第一个节点
item = head->data;
exhead->next = head->next;
exhead->data --;
free(head);//养成好习惯,不用了及时释放掉
}
return true;
}
按照我们一般的思路写到这肯定是没有问题的,但是没有问题就是最大的问题,这时候就会出现一种很神奇的情况,正常的插入删除都没问题,但是唯独把链表删空了之后,再进行插入就有问题了,我们会很神奇的发现链表的长度是对的,但是打印链表的时候,无论实际有几个点,只会输出一个点的data值,这到底是为什么呢?看到这,请先自己小小思考一会
想出来了,那么恭喜
没想出来,也没关系,我们一起来想
因为这时候统计队列长度只是通过返回rear->next->data实现的,并不会遍历整个链表,而且只会有一个值能进行输出,我们不妨大胆猜想,是不是链表断掉了,而且这种情况只会发生于在链表被删空之后,所以说问题就应当是在删除最后一个节点的时候产生的
我们来手动模拟一下
按照上面的操作, exhead正常指向附加头结点,head指向头结点,修改附加头结点的指针域,指向附加头结点自己,这时候我们发现并没有问题,附加头结点的data变成了0,而且指向自己,这不就跟初始化链表时候一样吗?真的完全一样吗?
整个链表的位置我们是通过rear获取的,要按说删空了之后,rear应该指向了附加头结点啊,但是这里并没有,所以说我们前面的问题也就能解释通了,那么如何解决呢?个人认为最简单的方式就是在只有一个节点的时候进行特判,直接进行一遍初始化就行了
if(rear->next->data == 1){
list nouse = rear->next;
item = rear->data;
rear->data = 0;
rear->next = rear;
free(nouse);
}
到站下车,感谢您的观看,谢谢了您馁