数据结构day5

 先导

        在写双链表之前,先复习一下线性表和链表的概念和特点。 

 线性表:由多个同一数据类型组成的线性结构,数据间具有一对一的关系。

 链表:链式存储的线性表,表中的元素物理地址不连续逻辑指针连续,逻辑上具有一一对应的关系。

 一、双链表的构成

         双链表中的元素(结点)由前向指针域、后向指针域和数据域组成,通过前向指针域和后向指针域将各个元素(结点)链接在一起,从而实现链表的双向链接。

        链表中的数据域分为头结点数据域和普通结点数据域,二者之间的区别是头结点数据域不存储任何数据只放链表的长度,普通结点数据域存储数据

        链表中的头结点除了起到标识作用外,不在起任何作用。也就是说头结点只是为了告诉你这是一个链表,不参与对数据的增添删改。对于前面所说的记录链表长度,其实是可以不要的,只是人为的想让它记录一下。若还不能理解,可以将其看做火车的司机车厢,在火车上司机车厢只负责将整条列车开往目的,其他一概不过问。

前向指针域:存储前一个结点的首地址

后向指针域:存储后一个结点的首地址

数据域:存储数据(普通结点)和链表的长度(头结点)

 二、双链表的链接示意图 

        链表中元素的物理地址不是连续的,需要使用指针将各个元素串联起来,进而实现逻辑上的连续,双链表也不例外。双链表中的pri和next都是指针,分别存放前一个结点的首地址和后一个结点的首地址,因此在链接的过程中实际上指向结点的首地址(如上图所示)。链接结点首地址相当于链上整个结点,故在链接的时候pri和next可以直接指向结点,但不能忘记址本质是指向结点的首地另外,在链接时,头结点的pri和最后一个结点的next需要指向NULL。

三、双链表结构体的定义

typedef int datatype;
typedef struct node
{
	union
	{
		datatype data;//普通结点数据域
		int len;//头结点数据域
	};
	struct node* pri;//前向指针域
	struct node* next;//后向指针域
}node,*node_p;

四、双链表的创建

         头结点的初始化需要在堆区申请空间,申请完毕后需要返回其首地址,告诉计算机这片地址是头结点。因此,函数的数据类型是指针类型。头结点的前向指针域和后向指针域的初始化不能省略。

/*---------------双链表的创建---------------*/
node_p create_double_link_list(void)
{
	node_p Head_node=(node_p)malloc(sizeof(node));
	if(Head_node==NULL)
	{
		printf("空间申请失败\n");
		return NULL;
	}
	Head_node->len=0;//头结点数据域的初始化
	Head_node->pri=NULL;//头结点前向指针域的初始化
	Head_node->next=NULL;//头结点后向指针域的初始化
	return Head_node;
}

五、双链表新节点的创建

        新结点的初始化需要在堆区申请空间,申请完毕后需要返回其首地址,告诉计算机这片地址是新结点。因此,函数的数据类型是指针类型。新节点的前向指针域和后向指针域的初始化可以省略。

/*------------双链表新节点的创建------------*/
node_p create_new_node_double_link_list(datatype newdata)
{
	node_p New_node=(node_p)malloc(sizeof(node));
	if(New_node==NULL)
	{
		printf("空间申请失败\n");
		return NULL;
	}
	New_node->data=newdata;//普通结点数据域的初始化
	New_node->pri=NULL;//普通结点前向指针域的初始化
	New_node->next=NULL;//普通结点后向指针域的初始化
	return New_node;
}

 六、双链表的判空

        双链表的判空,即判断双链表是不是只有头结点。当双链表只有头结点时,其pri和next指针域都指向NULL,故将其作为空的条件进行判断。判断完毕后,需要返回一个数值告诉我们是否为空,这里需要用到三目运算符“?:”。 

/*---------------双链表的判空---------------*/
int empty_double_link_list(node_p Head_node)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return -1;// 这种情况的返回值要往负数写,不要往正数写,正数返回值大多是需要用到的
	}
  	return Head_node->pri==NULL&&Head_node->next==NULL?1:0;
}

 七、双链表的输出

        双链表的输出和单链表一样,将结点依次后移,逐个输出即可。

/*---------------双链表的输出---------------*/
void show_double_link_list(node_p Head_node)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return;
	}
	if(empty_double_link_list(Head_node))
	{
		printf("双链表已空,无法输出\n");
		return;
	}
	node_p Show_node=Head_node->next;
	while(Show_node!=NULL)
	{
		printf("%d-->",Show_node->data);
		Show_node=Show_node->next;
	}
	printf("NULL\n");//人为的加上NULL,是为了让输出看起来更加完整
}

八、双链表的头插

        双链表的头插有两种情况:第一个结点存在和第一个结点不存在

        第一个结点存在(如下图所示):
                第一步,将新结点的next指针域指向原链表第一个结点的首地址。

                第二步,将原链表第一个结点的pri指针域指向新结点的首地址。

                第三步,将头结点的next指针域指向新结点的首地址。

                第四部,将新结点的pri指针域指向头结点的首地址。

        注意:第二步和第三步不能交换位置,若交换会导致新结点的pri指针域连上它自己,从而导致双链表不会链接成功。

        第一个结点不存在 (如下图所示):

        第一步,将新结点的next指针域指向NULL。

        第二步,将头结点的next指针域指向新结点的首地址。

        第三步,将新结点的pri指针域指向头结点的首地址。

        

         注意:第二种情况的头插与第一情况的头插相比,少了第一种情况的第二步。故在写程序时,只需添加一个if判断即可。

/*---------------双链表的头插---------------*/
void insert_head_double_link_list(node_p Head_node,datatype newdata)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return;
	}
	node_p New_node=create_new_node_double_link_list(newdata);
	New_node->next=Head_node->next;
	if(Head_node->next!=NULL)
	{
		Head_node->next->pri=New_node;
	}
	Head_node->next=New_node;
	New_node->pri=Head_node;
	Head_node->len++;
}

九、双链表的头删

/*---------------双链表的头删---------------*/
void delete_head_double_link_list(node_p Head_node)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return;
	}
	if(empty_double_link_list(Head_node))
	{
		printf("双链表已空,无法删除\n");
		return;
	}
	node_p Delete_node=Head_node->next;
	Head_node->next=Delete_node->next;
	if(Delete_node->next!=NULL)
	{
		Delete_node->next->pri=Head_node;
	}
	Delete_node->next=NULL;
	Delete_node->pri=NULL;
	free(Delete_node);
	Head_node->len--;
}

十、双链表的尾插

/*---------------双链表的尾插---------------*/
void insert_tail_double_link_list(node_p Head_node,datatype newdata)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return;
	}
	node_p Tail_node=Head_node;
	while(Tail_node->next!=NULL)
	{
		Tail_node=Tail_node->next;
	}
	node_p New_node=create_new_node_double_link_list(newdata);
	New_node->next=NULL;
	Tail_node->next=New_node;
	New_node->pri=Tail_node;
	Head_node->len++;
}

十一、双链表的尾删

/*---------------双链表的尾删---------------*/
void delete_tail_double_link_list(node_p Head_node)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return;
	}
	if(empty_double_link_list(Head_node))
	{
		printf("双链表已空,无法删除\n");
		return;
	}
	node_p Penultimate_node=Head_node;
	while(Penultimate_node->next->next!=NULL)
	{
		Penultimate_node=Penultimate_node->next;
	}
	node_p Delete_node=Penultimate_node->next;
	Penultimate_node->next=NULL;
	Delete_node->pri=NULL;
	free(Delete_node);
	Head_node->len--;
}

十二、双链表的按位置插入

/*------------双链表的按位置插入------------*/
void insert_pos_double_link_list(node_p Head_node,int pos,datatype newdata)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return;
	}
	if(pos<1||pos>Head_node->len+1)
	{
		printf("超出双链表范围,无法插入\n");
		return;
	}
	int i;
	node_p New_node=create_new_node_double_link_list(newdata);
	node_p Pos_node=Head_node;
	for(i=1;i<pos;i++)
	{
		Pos_node=Pos_node->next;
	}
	New_node->next=Pos_node->next;
	if(Pos_node->next!=NULL)
	{
		Pos_node->next->pri=New_node;
	}
	Pos_node->next=New_node;
	New_node->pri=Pos_node;
	Head_node->len++;
}

十三、双链表的按位置删除

/*------------双链表的按位置删除------------*/
void delete_pos_double_link_list(node_p Head_node,int pos)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return;
	}
	if(empty_double_link_list(Head_node))
	{
		printf("双链表已空,无法输出\n");
		return;
	}
	if(pos<1||pos>Head_node->len)
	{
		printf("超出双链表范围,无法删除\n");
		return;
	}
	int i;
	node_p Pos_node=Head_node;
	for(i=1;i<pos;i++)
	{
		Pos_node=Pos_node->next;
	}
	node_p Delete_node=Pos_node->next;
	Pos_node->next=Delete_node->next;
	if(Delete_node->next!=NULL)
	{
		Delete_node->next->pri=Pos_node;
	}
	Delete_node->next=NULL;
	Delete_node->pri=NULL;
	free(Delete_node);
	Head_node->len--;
}

十四、双链表的按值查找

/*-------------双链表的按值查找-------------*/
void search_data_double_link_list(node_p Head_node,datatype data)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return;
	}
	if(empty_double_link_list(Head_node))
	{
		printf("双链表已空,无法按值查找\n");
		return;
	}
	int arr[Head_node->len];
	int i,j=0;
	node_p Next_node=Head_node->next;
	for(i=1;i<=Head_node->len;i++)
	{
		if(Next_node->data!=data)
		{
			Next_node=Next_node->next;
		}
		else
		{
			arr[j]=i;
			Next_node=Next_node->next;
			j++;
		}
	}
	if(j!=0)
	{
		printf("该值对应的结点是\n");
		for(i=0;i<j;i++)
		{
			printf("第%d个结点\t",arr[i]);
		}
		printf("\n");
		return;
	}
	printf("该值不在此双循环链表中\n");	
}

 十五、双链表的按位置查找

/*------------双链表的按位置查找------------*/
datatype search_pos_double_link_list(node_p Head_node,int pos)
{
	if(Head_node==NULL)
	{
		printf("参数为空,请检查\n");
		return -1;
	}
	if(empty_double_link_list(Head_node))
	{
		printf("双链表已空,无法按位置查找\n");
		return -2;
	}
	if(pos<1||pos>Head_node->len)
	{
		printf("超出双链表范围,无法按位置查找\n");
		return -3;
	}
	int i;
	node_p Pos_node=Head_node->next;
	for(i=1;i<pos;i++)
	{
		Pos_node=Pos_node->next;
	}
	return Pos_node->data;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值