定义:循环链表是另一种形式的链式存储结构,它的特点是表中最后一个结点的指针指向头结点,整个链表形成一个环。由此,可以从表中任一结点出发均可寻找到表中其他结点。
定义:双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点
单向链表特点:
1.我们可以轻松的到达下一个节点, 但是回到前一个节点是很难的.
2.只能从头遍历到尾或者从尾遍历到头(一般从头到尾)
双向链表特点:
1.每次在插入或删除某个节点时, 需要处理四个节点的引用, 而不是两个. 实现起来要困难一些
2.相对于单向链表, 必然占用内存空间更大一些.
3.既可以从头遍历到尾, 又可以从尾遍历到头
双向链表中各节点包含以下 3 部分信息:
指针域:用于指向当前节点的直接前驱节点;
数据域:用于存储数据元素。
指针域:用于指向当前节点的直接后继节点;
typedef struct DuNode
{
int data; //数据域
struct DuNode* next; //后继
struct DuNode* pre; //前驱
}DuNode,*DuLinkList;
struct DuNode* head= NULL;
struct DuNode* end = NULL;
void AddListTill(int a )
{
//创建一个节点
struct DuNode* temp=(struct DuNode*)malloc(sizeof(struct DuNode)); //此处注意强制类型转换
//节点数据进行赋值
temp->data=a;
temp->next=NULL;
temp->pre=NULL;
//连接分两种情况
//1.一个节点都没有
//2.已经有节点了,添加到尾巴上
if(NULL==head)//没有节点
{
head=temp;
// end=temp;
}
else
{
end->next=temp;
// end=temp; //尾结点应该始终指向最后一个
}
end=temp; //尾结点应该始终指向最后一个
}
void AddListRand(int index,int a)
{
if (NULL==head)
{
printf("链表没有节点\n");
return;
}
struct DuNode* pt =FindNode(index);//添加之前需要找到该结点的位置
if(NULL==pt) //没有此节点
{
printf("没有指定节点\n");
return;
}
//有此节点
//创建临时节点,申请内存
struct DuNode* temp =(struct DuNode *)malloc(sizeof(struct DuNode));
if(temp== NULL)
{
printf("malloc error!\r\n");
return ;
}
//节点成员进行赋值
else{
temp->data=a;
temp->next=NULL;
temp->pre=NULL;
}
//连接到链表上
//1.找到的节点在尾部
//2.找到的节点在中间
if (pt == end)
{
//尾巴的下一个指向新插入的节点
end->next=temp;
//新的尾巴
temp->pre = end;
end=temp;
}else
{
// 先连后面 (先将要插入的节点指针指向原来找到节点的下一个)
temp->next=pt->next;
temp->pre = pt->pre;
//后连前面
pt->next=temp;
}
}
struct DuNode* FindNode(int a )//a是结点的序号
{
struct DuNode *temp =head;//创建一个临时结点为头结点
while(temp !=NULL)
{
if(a == temp->data)//找到该节点
{
return temp;
}
temp = temp->next;//依次顺序寻找
}
//没找到
return NULL;
}
void FreeList()
{
//一个一个NULL
struct DuNode *temp =head; //定义一个临时变量来指向头结点
while (temp !=NULL)
{
// printf("%d\n",temp->a);
struct DuNode* pt =temp;
temp = temp->next; //temp指向下一个的地址 即实现++操作
free(pt); //释放当前
}
//头尾清空 不然下次的头就接着0x10
head =NULL;
end =NULL;
}
/*更新函数,其中,add 表示更改结点在双链表中的位置,newElem 为新数据的值*/
Node *ModifyList(DuNode * p,int add,int newElem)
{
DuNode * temp=p;
/*遍历到被删除结点*/
for (int i=1; i<add; i++)
{
temp=temp->next;
}
temp->data=newElem;
return p;
}
void DeleteListTail()
{
if (NULL == end)
{
printf("链表为空,无需删除\n");
return;
}
//链表不为空
//链表有一个节点
if (head==end)
{
free(head);
head=NULL;
end=NULL;
}
else
{
//找到尾巴前一个节点
struct DuNode* temp =head;
while (temp->next!=end)
{
temp = temp->next;
}
//找到了,删尾巴
//释放尾巴
free(end);
//尾巴迁移
end=temp;
//尾巴指针为NULL
end->next=NULL;
}
}
void DeleteListHead()
{ //记住旧头
struct DuNode* temp=head;
//链表检测
if (NULL==head)
{
printf("链表为空\n");
return;
}
head=head->next;//头的第二个节点变成新的头
free(temp);
}
void DeleteListRand(int a)
{
//链表判断 是不是没有东西
if(NULL==head)
{
printf("链表没东西\n");
return;
}
//链表有东西,找这个节点
struct DuNode* temp =FindNode(a);//找到这个结点
if(NULL==temp)
{
printf("查无此点\n");
return;
}
//找到了,且只有一个节点
if(head==end)
{
free(head);
head=NULL;
end=NULL;
}
else if(head->next==end) //有两个节点
{
//看是删除头还是删除尾
if(end==temp)
{ DeleteListTail(); }
else if(temp==head)
{ DeleteListHead(); }
}
else//多个节点
{
//看是删除头还是删除尾
if(end==temp)
DeleteListTail();
else if(temp==head)
DeleteListHead();
else //删除中间某个节点
{ //找要删除temp前一个,遍历
struct DuNode* pt =head;
while(pt->next!=temp)
{
pt=pt->next;
}
//找到了
//让前一个直接连接后一个 跳过指定的即可
pt->next=temp->next;
free(temp);
}
}
}
/*输出链表的功能函数*/
void PrintList(DuNode * head)
{
DuNode * temp=head;
while (temp)
{
/*如果该节点无后继节点,说明此节点是链表的最后一个节点*/
if (temp->next==NULL)
{
printf("%d\n",temp->data);
}
else
{
printf("%d->",temp->data);
}
temp=temp->next;
}
}
void main ()
{
struct Node *pFind ;
//创建5个节点
for(i=0;i<6;i++)
AddListTill(i);
// AddListRand(4,14); //在指定位置4增加节点14
// DeleteListTail(); //删除一个尾结点
DeleteListRand(4); //删除4节点
ScanList(); //便利输出链表
FreeList(); //删除链表
/* pFind = FindNode(5); //查找5节点
if (pFind != NULL)
{
printf("找到%d\n",pFind->a); //找到节点并且输出该节点数据
}
else
{
printf("No Find!\n");
}
*/
}