算法与数据结构之四----双向链表

/****************************************************************
文件内容:线性表之循环链表操作
版本V1.0
说明:单链表必需从头结点开始遍历,而双链表可以可以往前后两个方向都可以遍历


1.赋值和指向方向不能搞错 A 赋值给B ,说明B指向A
2.双向链表跟普通链表操作思想一样,只不过多了一个前驱指针而已。
思路完全一致。
作者:HFL
时间:2013-12-29
 *****************************************************************/ 
#include<stdio.h>
#include<malloc.h>
#include <windows.h>
//#define RELEASE_VERSION  //release版本开关
//#define TRIDiTION
/*inlude<malloc.h> stdlib.h 包含malloc.h*/
#ifdef RELEASE_VERSION
#define  Log 
#else
#define  Log  printf
#endif


/*为了提高程序的可移植性,千万不能使用裸露的数据类型*/
#ifndef UINT32 
typedef unsigned int UINT32 ;
#endif
#ifndef INT32 
typedef  int  INT32 ;
#endif


typedef struct DNode
{
INT32 data;
struct DNode *prior,*next;
}Dnode,*Linklist;


/****************************************************************
函数功能:创建一个节点                        
输入参数:  无
返回值:节点的指针 
作者:HFL 
时间:2013-12-22
 *****************************************************************/
Linklist Creat_DNode(INT32 X)
{
 Linklist s;
      s=(struct DNode *)malloc(sizeof(DNode));
 if(NULL==s)
{
Log(" sorry,Malloc is failed\n");

}
else
{
Log(" Malloc is successed!\n");
s->data = X;
}
return s;
}
/****************************************************************
函数功能:初始化链表1(即头部创建一个链表)                        
输入参数:  无
返回值:链表的标头指针 
作者:HFL 
时间:2013-12-29
 *****************************************************************/ 
Linklist Head_Creat_Linklist()
{
Linklist L=NULL;
DNode *s;
INT32 x;
    scanf("%d",&x);
while(x!=0)
{
 s=(struct DNode *)malloc(sizeof(DNode));
 if(NULL==s)
{
Log(" sorry,Malloc is failed\n");

}
else
{
Log(" Malloc is successed!\n");
   s->next = L;
   s->data = x ;
if ( NULL != L)
{
L->prior = s; /*第一个节点再没有后面的节点了*/
}
L = s;
s->prior = L;
scanf("%d",&x);
}
}
return L;
}
/****************************************************************
函数功能:初始化链表2(即尾部创建一个链表)                        
输入参数:  无
返回值:链表的标头指针 
说明:要引入一个新的指针变量,用于链接前后节点
作者:HFL 
时间:2013-12-22
 ************T*****************************************************/ 
Linklist Tail_Creat_DLinklist()
{
Linklist L=NULL;


DNode *s;
DNode *probe =NULL;
INT32 x;
    scanf("%d",&x);
while(x!=0)
{
 s=(struct DNode *)malloc(sizeof(DNode));
 if(NULL==s)
{
Log(" sorry,Malloc is failed\n");

}
else
{
Log(" Malloc is successed!\n");
if(L== NULL)
{
L = s;  //第一个节点地址就必需保存到头节点
s->prior = L ;

}
else
{
probe->next = s; //第二个节点开始,要引入一个临时指针,来暂存上一个节点地址,一遍链接前后两个节点
s->prior = probe;
}
probe = s;  //每次创建一个新节点,节点都必需重新移动。

s->data = x ;
s->next = NULL;

scanf("%d",&x);
}
}
return L;
}
/****************************************************************
函数功能:从前往后遍历整个链表                        
输入参数:  链表头指针
返回值:无 
说明:遍历不能影响原来链表的结构。
作者:HFL 
时间:2013-12-22
 ************T*****************************************************/ 
void List_Back_Linklist(Linklist L)
{  
Linklist temp = L;//不能使用L指针,否则将链表头指针移动,链表被破坏,故使用一个临时指针来变量
INT32 i = 0;
if (NULL == L)
{
return ;
}
while(NULL!=temp)
{
printf("the data[%d]=%d\n",++i,temp->data);
//L->next=L->next->next;
temp = temp->next;
}
return ;
}
/****************************************************************
函数功能:从后往前遍历整个链表                        
输入参数:  链表头指针
返回值:无 
说明:遍历不能影响原来链表的结构。
作者:HFL 
时间:2013-12-29
 ************T*****************************************************/ 
void List_Head_Linklist(Linklist L,Linklist p)
{  
Linklist temp = p;//不能使用L指针,否则将链表头指针移动,链表被破坏,故使用一个临时指针来变量
INT32 i = 0;
if ( NULL == p )
{
return ;
}
    while(L != temp)
{
printf("the data[%d]=%d\n",++i,temp->data);
//L->next=L->next->next;
temp = temp->prior;
}

    printf("list the data[%d]=%d\n",++i,temp->data);
return ;
}
/****************************************************************
函数功能:按位置查找                        
输入参数:  链表头指针和位置i
返回值:  节点指针,如果无NULL,说明没有找到,否则说明找到,为temp指针指向的节点
说明:查找不能影响原来链表的结构。
作者:HFL 
时间:2013-12-29
 ************T*****************************************************/ 
Linklist Search_Position_Linklist(Linklist L,INT32 i)
{  
Linklist temp = L;//不能使用L指针,否则将链表头指针移动,链表被破坏,故使用一个临时指针来变量
INT32 position = 1;
while(NULL != temp && position != i)
{
temp = temp->next;
position++;
}
if (position < i)
{
printf("can't finded the postion!\n");
return NULL;
}
return temp;
}
/****************************************************************
函数功能:按值查找                        
输入参数:  链表头指针和位置i
返回值:  节点指针,如果为NULL,说明没有找到,否则说明找到,为temp指针指向的节点
说明:查找不能影响原来链表的结构。
作者:HFL 
时间:2013-12-29
 ************T*****************************************************/ 
Linklist Search_Value_Linklist(Linklist L,INT32 X)
{  
Linklist temp = L;//不能使用L指针,否则将链表头指针移动,链表被破坏,故使用一个临时指针来变量
INT32 position = 1;
while(NULL != temp && temp->data != X)
{
temp = temp->next;
position++;
}
if(temp == L && temp->data != X )
{
Log ("sorry ,can't finded the data\n");
}
else
{
    Log("The data is finded at positon[%d]\n",position);
}
return temp;
}
/****************************************************************
函数功能:从p节点按值向前查找                        
输入参数:  链表头指针和位置i
返回值:  节点指针,如果为NULL,说明没有找到,否则说明找到,为temp指针指向的节点
说明:查找不能影响原来链表的结构。
作者:HFL 
时间:2013-12-29
 ************T*****************************************************/ 
Linklist Search_Before_Value_Linklist(Linklist L,INT32 X,Linklist p)
{  
Linklist temp = p;//不能使用L指针,否则将链表头指针移动,链表被破坏,故使用一个临时指针来变量
INT32 position = 0;


if ( NULL == p )
{
return NULL;
}
while(L != temp && temp->data != X)
{
temp = temp->prior;
position++;
// Log ("hello\n");
}
if(temp == L && temp->data != X )
{
Log ("sorry ,can't finded the data\n");
}
else
{
    Log("The data is finded at back positon[%d]\n",position);
}
return temp;
}
/****************************************************************
函数功能: 从P节点后面插入k节点                     
输入参数:  链表头指针和p节点位置
返回值:   头节点
说明:   插入会改变节点的结构,如果是头节点插入,会修改头节点的。
作者:HFL 
时间:2013-12-29
 ****************************************************************/ 
Linklist Insert_Back_DLinklist(Linklist L, Linklist p,Linklist k)
{

if(NULL == L || NULL== k || NULL==p)
{
Log (" The linklist is null\n");
return NULL;
}
k->next=p->next;
p->next->prior= k;
p->next=k;
k->prior = p;
return L;


}
/****************************************************************
函数功能: 从P节点前面插入k节点                     
输入参数:  链表头指针和p节点位置
返回值:   头节点
说明:   插入会改变节点的结构,如果是头节点插入,会修改头节点的。
        前面插入要找前驱,效率低,一般使用双向链表,直接使用前驱指针
作者:  HFL
时间:2013-12-29
 ****************************************************************/ 
Linklist Insert_Front_DLinklist(Linklist L, Linklist p,Linklist k)
{
Linklist temp = L;
if(NULL == L || NULL== k || NULL==p)
{
Log (" The linklist is null\n");
return NULL;
}
k->next = p;
k->prior = p->prior;  /*顺序不能改,要先操作新节点,再操作老节点*/
p->prior->next = k;
p->prior = k;
return L;


}


/****************************************************************
函数功能: 从第i节点位置插入值为X的节点                    
输入参数:  链表头指针和p节点位置
返回值:   头节点
说明:   先找到i-1节点,然后在i-1节点后找出入一个节点,即i 位置的节点。
与单链表一样,只是底层实现不一样而已。
作者:HFL 
时间:2013-12-29  
 ****************************************************************/ 
Linklist Insert_i_Linklist(Linklist L,INT32 i,INT32 X)
{
Linklist temp = Search_Position_Linklist(L,i-1);
Linklist s = Creat_DNode(X);
if(!Insert_Back_DLinklist(L,temp,s))
{
Log(" Insert back of p node is failed \n");
return NULL ;
}
return L;
}


/****************************************************************
函数功能: 从P节点后面删除一个节点                     
输入参数:  链表头指针和p节点位置
返回值:   头节点
说明:   插入会改变节点的结构,如果是头节点插入,会修改头节点的。
作者:HFL 
时间:2013-12-2
 ****************************************************************/ 
Linklist Delete_Back_Linklist(Linklist L, Linklist p )
{
Linklist s;//删除后面的节点s
if(NULL == L || NULL== p)
{
Log (" The linklist is null\n");
return NULL;
}
s = p->next;
p->next = s->next;
s->next->prior = p; //指针可以一路连续指下去,但为了不出错,中间节点还是用s来保存
free(s);//注意是释放p 节点后面的节点,而不是p节点
return L;


}
/****************************************************************
函数功能: 从P节点前面删除s节点                     
输入参数:  链表头指针和p节点位置
返回值:   头节点
说明:   插入会改变节点的结构,如果是头节点插入,会修改头节点的。
        前面插入要找前驱,效率低,一般使用双向链表,直接使用前驱指针
作者:  HFL 
时间:2013-12-29
 ****************************************************************/ 
Linklist Delete_Front_Linklist(Linklist L, Linklist p)
{
Linklist s;
if(NULL == L || NULL==p)
{
Log (" The linklist is null\n");
return NULL;
}
s = p->prior;
s->prior->next = p;
p->prior = s->prior;
   
free (s); //释放I节点前的一个节点
return L;


}
/****************************************************************
函数功能: 删除第i节点                    
输入参数:  链表头指针和p节点位置
返回值:   头节点
说明:   先找到i-1节点,然后在i-1节点后找出入一个节点,即i 位置的节点。
作者:HFL 
时间:2013-12-29
 ****************************************************************/ 
Linklist Delete_i_Linklist(Linklist L,INT32 i)
{
Linklist temp = Search_Position_Linklist(L,i-1);
if(!Delete_Back_Linklist(L,temp))
{
Log(" Insert back of p node is failde \n");
return NULL ;
}
return L;
}
void main()
{  
Linklist L,temp;

Log("*******************************\n");
Log("*                             *\n");
Log("*   Creat DLinklist is start ! *\n");
Log("*                             *\n");
Log("*******************************\n");
   L = Tail_Creat_DLinklist();
   //L = Head_Creat_Linklist();
if(!L)
   {
      Log(" the Creat Linklist is failed\n");
   }
   else
   {
    Log(" the Creat Linklist is secuseed\n");
   }
    Log("*************************************\n");
Log("*                                   *\n");
Log("*   Back List DLinklist is  start ! *\n");
Log("*                                   *\n");
Log("*************************************\n");
List_Back_Linklist(L);
    Log("*************************************\n");
Log("*                                   *\n");
Log("*   Head List DLinklist is  start ! *\n");
Log("*                                   *\n");
Log("*************************************\n");
    // List_Head_Linklist(L,Search_Position_Linklist(L,5));
   List_Head_Linklist(L,Search_Before_Value_Linklist(L,12,Search_Position_Linklist(L,5)));
Insert_Back_DLinklist(L,Search_Position_Linklist(L,5),Creat_DNode(1000));
Log("*************************************************\n");
Log("*                                               *\n");
Log("*   Insert P Node In DLinklist back is  start ! *\n");
Log("*                                               *\n");
Log("*************************************************\n");
List_Back_Linklist(L);
Log("*************************************************\n");
Log("*                                                *\n");
Log("*   Insert P Node In DLinklist front is  start ! *\n");
Log("*                                                *\n");
Log("**************************************************\n");
Insert_Front_DLinklist(L,Search_Position_Linklist(L,5),Creat_DNode(999));
List_Back_Linklist(L);
Log("*************************************************\n");
Log("*                                                *\n");
Log("*   Insert I Node In DLinklist front is  start ! *\n");
Log("*                                                *\n");
Log("**************************************************\n");
Insert_i_Linklist(L,5,2222);
List_Back_Linklist(L);
Log("*************************************************\n");
Log("*                                                *\n");
Log("*   Delete P Node In DLinklist back is  start ! *\n");
Log("*                                                *\n");
Log("**************************************************\n");
Delete_Back_Linklist(L,Search_Position_Linklist(L,5));
List_Back_Linklist(L);
Log("*************************************************\n");
Log("*                                                *\n");
Log("*   Delete P Node In DLinklist front is  start ! *\n");
Log("*                                                *\n");
Log("**************************************************\n");
Delete_Front_Linklist(L,Search_Position_Linklist(L,5));
List_Back_Linklist(L);
Log("*************************************************\n");
Log("*                                                *\n");
Log("*   Delete P Node In DLinklist  is  start ! *\n");
Log("*                                                *\n");
Log("**************************************************\n");
Delete_i_Linklist(L,5);
List_Back_Linklist(L);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江海细流

如该文章对你有帮助,请支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值