Data structure - basic operation of double linked list (C language implementation)

Reference book: Wang Daoyan data structure

(This post is the blogger’s notes on learning 408. Because the blogger is also a learner, please correct me if there are any mistakes in my personal summary. If there is any infringement, please let me know and delete it immediately to apologize)​​​​

One: The meaning of double linked list

        The double-linked list is based on the single-linked list with a prior pointer pointing to the predecessor node. This solves the pain point problem that the single-linked list can only find the successor and cannot find the predecessor node, because the single-linked list has only one next pointer pointing to the successor, so that the single-linked list can only be traversed sequentially from the beginning to the end.

        The value search and bitwise search of the double linked list are the same as the single linked list, but the addition and deletion operations are different from the single linked list. Not only must the successor pointer be modified, but also the prior predecessor pointer should be modified. During this process, care should be taken not to break the link! !

 Two: Insert operation demonstration of double linked list


Core operations:

①s->next = p->next;

②p->next->prior = s;

③s->prior = p;

④p->next = s;

Three: double linked list deletion 

Core operations:

1.p->next = q->next;

2.q->next->prior = p;

Four: The rest of the operations are basically the same as those of the singly linked list.

 

#include <stdio.h>
#include <stdlib.h>

/**********************************************
制作人:祝星。
项目名称:数据结构-双链表的基本操作(C语言实现)
完成时间:2022年7月0日
完成内容:双链表的创建,修改,增加,删除,销毁。
具体内容,尾插法,按位查找,按位删除,求表长,遍历输出,销毁双链表
运行环境:win10
程序环境:VC++
文件语言:C语言
文件类型:.cpp
注:1.VC++的.cpp环境,&为取地址。
	2.LNode *等价于LinkList,前者强调这是结点,后者强调这是链表,合适的地方使用合适的名字,代码可读性更高。

  注意:剩余操作与单链表一致,无非是多一步操作,在next指针指向后,修改prior指针,并且保证不断链。
		建议读者在学习链表等数据结构时画图理解更直观。
***********************************************/

#define Max 10  

/**定义一个具有前驱指针和后继指针的双链表的结构体**/
typedef struct DNode{
	int data;	//数据域
	struct DNode *prior,*next;		//前驱指针和后继指针
}DNode,*DLinkList;         //前者强调这是结点,后者强调这是链表

/**
	初始化一个双链表,其前驱指针和后继指针指向NULL
	除非连接为循环链表,否则prior指针永远指向NULL
**/
DLinkList InitDLinkList(DLinkList &L){
	int x; //输入data值
	L = (DLinkList)malloc(sizeof(DNode)); //申请链表的头结点
	DNode *s,*r = L;//初始化两个结点指针指向头结点
	if(L==NULL)			//没有申请到内存空间则返回false
		return false;
	L->prior=NULL;
	L->next=NULL;

	printf("输入(9999结束)");
	scanf("%d",&x);//输入插入的值,输入9999结束
	while(x!=9999){
		s = (DNode*)malloc(sizeof(DNode));//动态申请一个存放插入值的结点
		s->data=x;//将输入的值赋值给新申请结点
		r->next=s;//将指向头结点的r的next指针指向s
		s->prior=r;//将新节点的前驱指针指向上一个
		r=s;//将r的指针指向s新节点
		printf("输入(9999结束)");
		scanf("%d",&x);
	}
	r->next=NULL;//r的next指针指向NULL
	return L;
}

/**
	双链表的插入操作
**/
bool InsertNextDNode(DNode *p,DNode *s){
	if(p==NULL || s==NULL)
		return false;
	s->next=p->next;
	if(p->next !=NULL)
		p->next->prior = s;   
	s->prior = p;
	p->next = s;
	return true;
}

/*******************************
函数名:按位查找
参数:L,i
返回值:返回结点指针值
*******************************/
DNode *GetElem(DLinkList L,int i){
	int j=1;//因为有头结点,所以从1开始遍历
	if(i<1){//判断查找的位置是否合法
		printf("数值非法");
	}
	DNode *p = L->next;//初始化结点指针
	while(p!=NULL&&j<i){
		p=p->next;
		j++;
	}
	return p;
}

/*******************************
函数名:按位删除结点
参数:L,i
返回值:返回结点指针值
*******************************/
DLinkList DeleteNode(DLinkList &L,int i){
	DNode *p;
	p=GetElem(L,i);//调用按位查找函数
	if(p==NULL)
		return false;
	if(p->next!=NULL){
		p->prior->next = p->next;//p的前驱的后继指针指向p的后继
		p->next->prior=p->prior;//p的后继的前驱指针指向p的前驱
		free(p);	//释放
	}
	return L;
	/*
	第二种方法,和单链表一样找到P的前驱结点,也就是i-1,此方法是王道书中的删除核心操作
	DNode *p,*q;
	p=GetElem(L,i-1);//调用按位查找函数
	if(p==NULL)
		return false;
	q=p->next;
	if(q!=NULL){
		p->next = q->next;
		q->next->prior = p;
		free(p);	//释放
	}
	return L;
	*/

}

/*指定结点的后插*/
DLinkList InsertNextNode(DLinkList &L,DNode *p,int e){
	if(p==NULL)
		return false;
	DNode *s = (DNode*)malloc(sizeof(DNode));//申请不到内存空间则返回false
	if(s==NULL)
		return false;
	s->data=e;
	s->next=p->next;
	p->next->prior = s;
	s->prior = p;
	p->next=s;
	return L;
}
/*指位序后插入*/
DLinkList InsertNNode(DLinkList &L,int i,int e)
{
	if(i<1)
		return false;
	DNode *s;
	int j=0;
	s=L;
	while(s!=NULL&&j<i)
	{
		s=s->next;
		j++;
	}
	if(s==NULL)
		return false;
	
	return InsertNextNode(L,s,e);
}
 

/*求表长*/
int Length(DLinkList L)
{
	int len=0;
	DNode *p=L;
	while (p->next!=NULL)
	{
		p=p->next;
		len++;
	}
	return len;
}

/*遍历输出*/
void Show(DLinkList L){
	printf("当前单链表的所有元素:【head】<=>");
	DNode *p;
	p =L->next;
	while(p!=NULL){
		printf("[%d]<=>",p->data);
		p=p->next;
	}
	printf("NULL");
	printf("\n");
	printf("当前表长为%d\n",Length(L));
	printf("-----------------------------------------------------------\n");
}
/***
	彻底销毁链表各个节点,并将销毁后的链表指向null
  */
void DestroyList(DLinkList &L)
{
	
	DNode *p ,*q;//初始化两个指针,p用来free释放,q用来在p释放后将p指针指向下一个
	p= L->next;//删除带头链表头结点不删除
	q=p;		
	while(p!=NULL){
		q=p->next;  //提前将q指向下一个
		free(p);	//释放p
		p = q;		//将p指向q所指向的下一个
	}
	L->next = NULL; //头结点指向NULL
	printf("\n销毁成功\n");
}

int main(){
	DLinkList(l);
	l = InitDLinkList(l);
	Show(l);
	DeleteNode(l,3);
	printf("删除第三个位置的元素后:");
	Show(l);
	printf("在第二个位置后插入99:");
	InsertNNode(l,2,99);
	Show(l);
	return 0;
}


Guess you like

Origin blog.csdn.net/weixin_44449779/article/details/125893263