自定義雙向迴圈連結串列基本函式介面

林大官人995發表於2024-04-24

自定義雙向迴圈連結串列的函式介面

/*******************************************************************
*
*	檔名稱  :	雙向迴圈連結串列的函式介面
*	檔案作者  : mailLinL@163.com 
*	建立日期  :  2024/04/24
*	檔案功能  :  對雙向連結串列的增刪改查功能的定義
* 	注意事項  :  None
*
*	CopyRight (c)  2024   mailLinL@163.com   All Right Reseverd 
*
* *****************************************************************/

指的是雙向連結串列中的結點有效資料型別,使用者可以根據需要進行修改

typedef int  DataType_t;

構造雙向連結串列的結點,連結串列中所有結點的資料型別應該是相同的

typedef struct Double_Cric_Linked_List
{
	DataType_t  		     data; //結點的資料域
	struct DoubleCricLList_t	*prev; //直接前驅的指標域
	struct DoubleCricLList_t	*next; //直接後繼的指標域

}DoubleCricLList_t;

建立雙向連結串列,並建立管理雙向迴圈連結串列的頭結點

/*******************************************************************
*
*	函式名稱:	DoubleCricLList_Create
*	函式功能:   建立雙向連結串列,並建立管理雙向迴圈連結串列的頭結點
* 	函式引數:	none
*   返回結果:   
* 	注意事項:   None
* 	函式作者:   mailLinL@163.com
*	建立日期:   2024/04/24
*	修改歷史:	
*	函式版本:	V1.0
* *****************************************************************/

//建立一個空雙向迴圈連結串列,空連結串列應該有一個頭結點,對連結串列進行初始化
DoubleCricLList_t * DoubleCricLList_Create(void)
{
	//1.建立一個頭結點並對頭結點申請記憶體
	DoubleCricLList_t *Head = (DoubleCricLList_t *)calloc(1,sizeof(DoubleCricLList_t));
	if (NULL == Head)
	{
		perror("Calloc memory for Head is Failed");
		exit(-1);
	}

	//2.對頭結點進行初始化,頭結點是不儲存資料域,指標指向自身,體現“迴圈”
	Head->prev = Head;
	Head->next = Head;

	//3.把頭結點的地址返回即可
	return Head;
}

建立新的雙向迴圈連結串列結點

/*******************************************************************
*
*	函式名稱:	DoubleCricLList_NewNode
*	函式功能:   建立新的雙向迴圈連結串列結點
* 	函式引數:	
*			   @data  : 傳入結點的資料域的值
*   返回結果:   
*			   @New  : 返回新結點地址便於操作
* 	注意事項:   None
* 	函式作者:   mailLinL@163.com
*	建立日期:   2024/04/23
*	修改歷史:	
*	函式版本:	V1.0
* *****************************************************************/

DoubleCricLList_t * DoubleCricLList_NewNode(DataType_t data)
{
	//1.建立一個新結點並對新結點申請記憶體
	DoubleCricLList_t *New = (DoubleCricLList_t *)calloc(1,sizeof(DoubleCricLList_t));
	if (NULL == New)
	{
		perror("Calloc memory for NewNode is Failed");
		return NULL;
	}

	//2.對新結點的資料域和指標域(2個)進行初始化	指向自身 體現“迴圈”
	New->data = data;
	New->prev = New;
	New->next = New;

	return New;
}

向雙向迴圈連結串列中的頭部插入新結點

/*******************************************************************
*
*	函式名稱:	DoubleCricLList_HeadInsert
*	函式功能:   向雙向迴圈連結串列中的頭部插入新結點
* 	函式引數:	
*			    @Head    :傳入需要操作的連結串列頭結點
*			    @data    :傳入需要插入的新結點的資料
*   返回結果:   
*				
* 	注意事項:   None
* 	函式作者:   mailLinL@163.com
*	建立日期:   2024/04/23
*	修改歷史:	
*	函式版本:	V1.0
* *****************************************************************/

bool DoubleCricLList_HeadInsert(DoubleCricLList_t *Head,DataType_t data)
{
	//1.建立新結點,定義指標記錄新結點的地址
	DoubleCricLList_t *New=DoubleCricLList_NewNode(data);

	//2.判斷新結點是否申請成功
	if(NULL==New){
		printf("Calloc memory for NewNode is Failed");
		return false;
	}

	//3.當需要操作的連結串列為空
	if(Head->next==Head){
		Head->next=New;				//將頭結點的next指標指向新結點的地址
		return true;
	}

	//4.當需要操作的連結串列非空時
	DoubleCricLList_t *Phead=Head->next;	//記錄首結點的地址

	//當連結串列只有一個結點時 即首結點的next指標指向的地址是它自身
	if(Phead->next==Phead){
		Phead->next=New;				//將首結點的next指標指向New的地址
		Phead->prev=New;				//將首結點的prev指標指向New的地址
		New->next=Phead;				//將新結點的next指標指向首結點
		New->prev=Phead;				//將新結點的prev指標指向首結點
	}
	//當連結串列不止一個結點時 即首結點的next指標指向的地址不是它自身
	else if(Phead->next!=Phead){
		Phead->prev->next=New;			//將尾結點的next指標指向新結點
		New->prev=Phead->prev;			//將新結點的prev指標指向尾結點
		New->next=Phead;				//將新結點的next指標指向首結點
		Phead->prev=New;				//將首結點的prev指標指向新結點
		Head->next=New;					//將頭結點的next指標指向新結點
	}
	return true;
}

向雙向迴圈連結串列中的尾部插入新結點

/*******************************************************************
*
*	函式名稱:	DoubleCricLList_TailInsert
*	函式功能:   向雙向迴圈連結串列中的尾部插入新結點
* 	函式引數:
*			    @Head    :傳入需要操作的連結串列頭結點
*			    @data    :傳入需要插入的新結點的資料
*	返回結果:
* 	注意事項:   None
* 	函式作者:   mailLinL@163.com
*	建立日期:   2024/04/23
*	修改歷史:
*	函式版本:	V1.0
* *****************************************************************/
bool DoubleCricLList_TailInsert(DoubleCricLList_t *Head,DataType_t data)
{
	//1.建立新結點,定義指標記錄新結點的地址
	DoubleCricLList_t *New=DoubleCricLList_NewNode(data);
	
	//2.判斷新結點是否申請成功
	if(NULL==New){
		printf("Calloc memory for NewNode is Failed");
		return false;
	}

	//3.當需要操作的連結串列為空
	if(Head->next==Head){
		Head->next=New;				//將頭結點的next指標指向新結點的地址
		return true;
	}

	//4.當連結串列非空時,定義指標記錄首結點的地址
	DoubleCricLList_t *Phead=Head->next;
	//當連結串列只有一個結點時 即首結點的next指標指向的地址是它自身
	if(Phead->next==Phead){
		Phead->next=New;				//將首結點的next指標指向New的地址
		Phead->prev=New;				//將首結點的prev指標指向New的地址
		New->next=Phead;				//將新結點的next指標指向首結點
		New->prev=Phead;				//將新結點的prev指標指向首結點
	}

	//當連結串列不止一個結點時 即首結點的next指標指向的地址不是它自身
	else if(Phead->next!=Phead){
		Phead->prev->next=New;			//將尾結點的next指標指向新結點
		New->prev=Phead->prev;			//將新結點的prev指標指向尾結點
		New->next=Phead;				//將新結點的next指標指向首結點
		Phead->prev=New;				//將首結點的prev指標指向新結點
	}
	return true;
}

向雙向迴圈連結串列中的目標結點後插入新結點

/*******************************************************************
*
*	函式名稱:	DoubleCricLList_DestInsert
*	函式功能:   向雙向迴圈連結串列中的目標結點後插入新結點
* 	函式引數:
*			    @Head    :傳入需要操作的連結串列頭結點
*			    @data    :傳入需要插入的新結點的資料
*			    @destval :傳入目標結點的資料域的值
*	返回結果:
* 	注意事項:   None
* 	函式作者:   mailLinL@163.com
*	建立日期:   2024/04/24
*	修改歷史:
*	函式版本:	V1.0
* *****************************************************************/
bool DoubleLList_DestInsert(DoubleCricLList_t *Head,DataType_t data,DataType_t destval)
{
	//1.建立新結點,定義指標記錄新結點的地址
	DoubleCricLList_t *New=DoubleLList_NewNode(data);
	

	//2.判斷新結點是否申請成功
	if(NULL==New){
		printf("Calloc memory for NewNode is Failed");
		return false;
	}
	
	//3.當需要操作的連結串列為空,即沒有目標結點,插入失敗
	if(Head->next==Head){
		printf("No target node!");
		return false;
	}

	//備份首結點的地址
	DoubleCricLList_t *Phead=Head->next;

	//4.遍歷連結串列尋找目標結點
	while(Phead->data!=destval){
		Phead=Phead->next;
		if(NULL==Phead->next){			//當遍歷到尾結點直接前驅時,直接前驅的next指標指向的地址下的資料與目標資料不同 沒有目標結點 退出程式
			printf("No target node!");
			return false;
		}
	}
	
	//5.在目標結點後插入新結點
	//當目標結點是唯一節點
	if(Phead->next==Phead){
		Phead->next=New;				//將首結點的next指標指向New的地址
		Phead->prev=New;				//將首結點的prev指標指向New的地址
		New->next=Phead;				//將新結點的next指標指向首結點
		New->prev=Phead;				//將新結點的prev指標指向首結點
	}
	//當目標結點不是尾結點
	else if(Phead->next!=Head->next){
		Phead->next->prev=New;			//將目標結點直接後繼的prev指標指向新結點
		New->next=Phead->next;			//將新結點的next指標指向目標結點的直接後繼
		Phead->next=New;				//將目標結點的next指標指向新結點
		New->prev=Phead;				//將新結點的prev指標指向目標結點
	}
	//如果目標結點是尾結點
	else{
		Phead->prev->prev=New;			//將首結點的prev指標指向新結點
		New->next=Phead->prev;			//將新結點的next指標指向首結點
		Phead->next=New;				//將尾指標的next指標指向新結點
		New->prev=Phead;				//將新結點的prev指標指向原尾結點
	}
	return true;
}

刪除雙向迴圈連結串列中的首結點

/*******************************************************************
*
*	函式名稱:	DoubleCricLList_HeadDel
*	函式功能:   刪除雙向迴圈連結串列中的首結點
* 	函式引數:
*			   @Head :傳入需要操作的連結串列的頭結點
*	返回結果:
* 	注意事項:   None
* 	函式作者:   mailLinL@163.com
*	建立日期:   2024/04/24
*	修改歷史:
*	函式版本:	V1.0
* *****************************************************************/
bool DoubleCricLList_HeadDel(DoubleCricLList_t *Head)
{
	//1.判斷連結串列是否為空
	if(Head->next==NULL){
		printf("Double linked list is empty!\n");
		return false;
	}
	
	//2.備份首結點的地址
	DoubleCricLList_t *Phead=Head->next;

	//3.如果非空,判斷連結串列是否僅有一個結點
	if(Phead->next==Phead){
		Phead->next=NULL;					//將首結點的next指標指向NULL
		Phead->prev=NULL;					//將首結點的prev指標指向NULL
		Head->next=Head;					//將頭結點的next指標指向自身  體現“迴圈”
		free(Phead);						//釋放首結點的記憶體空間
	}

	//4.如果不是隻有一個結點
	else if(Phead->next!=Phead){
		Phead->prev->next=Phead->next;		//將尾結點的prev指標指向首結點直接後繼的地址
		Phead->next->prev=Phead->prev;		//將首結點直接後繼的prev指標指向尾結點的地址
		Head->next=Phead->next;				//將頭結點的next指標指向首結點直接後繼的地址
		Phead->next=NULL;					//將首結點的next指標指向NULL
		Phead->prev=NULL;					//將首結點的prev指標指向NULL
		free(Phead);						//釋放原首結點的記憶體空間
	}
}

刪除雙向迴圈連結串列中的尾結點

/*******************************************************************
*
*	函式名稱:	DoubleCricLList_TailDel
*	函式功能:   刪除雙向迴圈連結串列中的尾結點
* 	函式引數:
*			   @Head :傳入需要操作的連結串列的頭結點
*	返回結果:
* 	注意事項:   None
* 	函式作者:   mailLinL@163.com
*	建立日期:   2024/04/23
*	修改歷史:
*	函式版本:	V1.0
* *****************************************************************/
bool DoubleCricLList_TailDel(DoubleCricLList_t *Head)
{
	//1.判斷連結串列是否為空
	if(Head->next==Head){
		printf("Double linked list is empty!\n");
		return false;
	}

	//2.備份首結點的地址及尾結點的地址
	DoubleCricLList_t *Phead=Head->next;
	DoubleCricLList_t *Last=Head->next->prev;

	//3.刪除尾結點
	//當連結串列中只有一個結點
	if(Phead->next==Phead){
		Phead->next=NULL;					//將首結點的next指標指向NULL
		Phead->prev=NULL;					//將首結點的prev指標指向NULL
		Head->next=Head;					//將頭結點的next指標指向自身  體現“迴圈”
		free(Phead);						//釋放首結點的記憶體空間
	}
	//當連結串列不止有一個節點
	else if(Phead->next!=Phead){
		Last->prev->next=Phead;				//將尾結點直接前驅的next指標指向首結點地址
		Phead->prev=Last->prev;				//將首結點的prev指標指向尾結點直接前驅地址
		Last->next=NULL;					//將尾結點的next指標指向NULL
		Last->prev=NULL;					//將尾結點的prev的指標指向NULL
		free(Last);							//釋放原尾結點的記憶體空間
	}
	return true;
}

刪除雙向迴圈連結串列中的指定結點

/*******************************************************************
*
*	函式名稱:	DoubleCricLList_t_DestDel
*	函式功能:   刪除雙向迴圈連結串列中的指定結點
* 	函式引數:
*			   @Head    :傳入需要操作的連結串列的頭結點
*			   @destval :傳入與目標結點資料與相同的數值
*	返回結果:
* 	注意事項:   None
* 	函式作者:   mailLinL@163.com
*	建立日期:   2024/04/23
*	修改歷史:
*	函式版本:	V1.0
* *****************************************************************/
bool DoubleCricLList_DestDel(DoubleCricLList_t *Head,DataType_t destval)
{
	//1.判斷連結串列是否為空
	if(Head->next==Head){
		printf("Double linked list is empty!\n");
		return false;
	}
	
	//2.備份首結點的地址
	DoubleCricLList_t *Phead=Head->next;

	//3.遍歷尋找連結串列中的目標結點
	while(Phead->data!=destval){
		if(Head->next==Phead->next){
			return false;
		}
		Phead=Phead->next;
	}

	//4.刪除目標結點
	//當連結串列只有一個結點
	if(Phead->next==Head->next){
		Phead->next=NULL;					//將目標結點的next指標指向NULL
		Phead->prev=NULL;					//將目標結點的prev指標指向NULL
		Head->next=Head;					//將頭結點的next指標指向自身  體現“迴圈”
		free(Phead);						//釋放首結點的記憶體空間
	}
	//當連結串列不止有一個節點
	else if(Phead->next!=Head->next){
		Phead->prev->next=Phead->next;		//將目標結點直接前驅的next指標指向目標結點直接後繼的地址
		Phead->next->prev=Phead->prev;		//將目標結點直接後繼的prev指標指向目標結點直接前驅的地址
		if(Head->next=Phead){				//當目標結點正好是首結點時
			Head->next=Phead->next;			//將頭結點的next指標指向首結點直接後繼的地址
		}
		Phead->next=NULL;					//將目標節點的next指標指向NULL
		Phead->prev=NULL;					//將目標結點的prev指標指向NULL
		free(Phead);						//釋放目標結點空間記憶體
	}
	return true;
}

總結:

雙向迴圈連結串列與雙向不迴圈連結串列的差別只有首結點有無直接前驅以及尾結點有無直接後繼
雙向迴圈連結串列中頭結點在連結串列為空時,next指標指向自身地址
操作雙向連結串列的首結點及尾結點時,一定要注意首結點prev指標以及尾結點next指標的指向問題
向雙向迴圈連結串列中首結點前及尾結點後插入新結點時,不要忘記首結點prev指標以及尾結點next指標的指向問題

相關文章