大二学数据结构的时候没好好做题,导致现在有关数据结构这方面的题做起来都比较费劲,就想着抽空重新自学一下。首先肯定是要先自学一下链表的建立,但是毕竟还是有一点基础的。就不从头插法尾插法开始学起了,我觉得能把这个双向循环链表熟练的建立然后输出出来正常的建一个单向,不管正向逆向应该都是信手拈来了。
自学的代码如下(如果有什么建议的话可以直接评论或私信我):
#include <bits/stdc++.h>
using namespace std;
struct node
{
int data; //存数据的位置
struct node *next; //指向下一个结点
struct node *last; //指向上一个结点
}*p, *q, *head; //head是链表的头,p和q都是移动指针,p负责赋值用,q负责结点指向位置的确定
int main()
{
int n, m;
scanf("%d", &n);
m = n;
head = (struct node *)malloc(sizeof(struct node));
//head是链表的第一个元素;目的是找到链表所在,除它以外的指针都是移动的。
q = head; //q为移动指针,指向我们要插入的元素的前一个,首先要等于head不然链表联系不起来
while(m--) //m个元素
{
p = (struct node *)malloc(sizeof(struct node)); //给刚出现的结点一个新的空间
scanf("%d", &p->data);
p -> next = NULL; //p的下一个结点还未出现,先赋成空,要明确每个指针指向的位置
q -> next = p; //q是p的上一个指针,那么p是q的下一个指针,所以q的next指向p
p -> last = q; //q是p的上一个,所以p的last指向q
q = p; //当下一次建立新节点p时,才能保证每次p都是在上一个p的后面
}
/*
分析循环结束时的状态:
p -> next = NULL; 说明最后一个结点的next是空。
p -> last = q; 说明最后一个结点的last指向上一个结点。
此时最后一个结点分析完了;
然后分析头(head):第一次进入循环的时候有一个 q -> next = p; 第一次的q就是head;
所以head下一个指向整个链表的第一个带data的结点(head自己不带的)。
总结:最后一个结点next指向的空,head的last指向的不知道,因为没初始head->last = NULL;
*/
p -> next = head -> next; //最后一个结点的next指向第一个元素,此时正向便可以循环了。
head -> last = p; //head的上一个结点指向最后一个结点p
q = head -> next; //q此时待变第一个带元素的结点
q -> last = head -> last; //第一个元素的last指向head的last也就是最后一个元素。此时逆向也可以循环了。
m = n*2;
while(m--)
{
printf("%d -> ", q->data);
q = q->next; //正向循环输出两遍这个链表,代表链表已接起来
}
q = head -> last;
printf("\n");
m = n *2;
while(m--)
{
printf("%d <- ", q->data);
q = q->last; //逆向循环输出两边链表,代表逆向也连接正常,此时可证明双向循环链表已经可以使用了,链表一共有n个元素。
}
return 0;
}
自学的时候画个图就会很清晰的。比如分析的时候,可以把分析结果用图像的时候表示。
/*
分析循环结束时的状态:
p -> next = NULL; 说明最后一个结点的next是空。
p -> last = q; 说明最后一个结点的last指向上一个结点。
此时最后一个结点分析完了;
然后分析头(head):第一次进入循环的时候有一个 q -> next = p; 第一次的q就是head;
所以head下一个指向整个链表的第一个带data的结点(head自己不带的)。
总结:最后一个结点next指向的空,head的last指向的不知道,因为没初始head->last = NULL;
*/
目标就是:p的next指向head的next;head和head后面的结点的last指向p;
运行结果: