【數據結構】單鏈表刪除數據爲x的元素(遞歸&非遞歸)

單鏈表刪除元素時,可以按序號刪除,也可以按數據刪除。
這裏寫的是,不帶頭結點的單鏈表的按數據刪除節點。

首先遞歸方式:

void Delete_x1(LinkList &L,int x){		//刪除無頭結點鏈表值爲x的節點 
	LinkList p;							//遞歸刪除 
	if(L==NULL)
		return ;
	if(L->data==x){				 
		p=L;				//讓p指向了數據域與x相等的節點 
		L=L->next;			//指向值爲x節點的指針直接指向了下一個節點 
		free(p);			//釋放p節點,這裏並不會斷鏈 
		Delete_x1(L,x);
	}
	else
		Delete_x1(L->next,x);
}

第一次接觸遞歸刪除的時候肯定會覺得直接刪除該節點了,那麼鏈表是會斷開的。
其實,在上面的寫法中,鏈表是不會斷開的。遞歸開始寫明結束條件,L==NULL(這裏是不帶頭結點的鏈表)。然後如果遇到值爲x的節點了,需要刪除。L=L->next;直接就把這個等於x的節點刪除了,那麼前面的鏈爲什麼不會斷呢,因爲這裏的L就是上一個節點指向x的指針,現在直接把L指向了x的下一個,所以就不會斷開了。
做個圖瞭解一下:
在這裏插入圖片描述
然後是非遞歸方式:

void Delete_x2(LinkList &L,int x){		//非遞歸方法 
	LinkList p,q;
	LinkList pre;
	pre=(LinkList)malloc(sizeof(LNode));
	while(L->data==x){
		q=L;
		L=L->next;
		free(q);
	}
	p=L;
	pre->next=p;						//創建pre作爲p的前驅指針 
	while(p!=NULL){
		if(p->data==x){	
			q=p;				
			pre->next=p->next;
			p=pre->next;
			free(q);
		}
		else{
			pre=p;
			p=p->next;
		}
	}
	return ;
}

這個沒有頭節點的就是麻煩一點,需要對第一個節點進行單獨說明。現在知道引入頭節點的好處了,首先如果刪除的元素就在第一個的話,就需要直接刪除,如果有多個的話就需要一直刪一直刪。
就上面這種寫法的話會有一個問題,就是如果一個鏈表的所有值都是x的話,那麼就會一直刪一直刪x.x.x.x.x…然後鏈表的每一個節點都被銷燬了,然後鏈表就不存在了。
下面是大概的單鏈表的無頭節點的一個框架:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;

typedef int ElemType;
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode,*LinkList;

LinkList InitList(LinkList &L){
	L=(LinkList)malloc(sizeof(LNode));
	//L->next=NULL;				//帶頭結點的單鏈表 
	L=NULL; 
	return L;
}

LinkList ListInsert_Head(LinkList &L,int n){
	LinkList p;
	p=new LNode;
	cin >> p->data;
	p->next=NULL;
	L=p;
	n--;
	while(n--){
		p=new LNode;
		cin >> p->data;
		p->next=L->next;
		L->next=p; 
	}
	return L;
}

LinkList ListInsert_Tail(LinkList &L,int n){
	LinkList p;
	LinkList r;
	p=new LNode;
	cin >> p->data;
	L=p;
	r=L;
	n--;
	while(n--){
		p=new LNode;
		cin >> p->data;
		p->next=NULL;
		r->next=p;
		r=p;
	}
	return L;
}

LinkList TraveList(LinkList &L){
	LinkList p;
	int length=0;
	p=L;
	while(p){
		cout << p->data << " ";
		p=p->next;
		length++;
	}
	cout << endl;
	cout << "The length is " << length << endl;
	return L;
}

void Delete_x1(LinkList &L,int x){		//刪除無頭結點鏈表值爲x的節點 
	LinkList p;							//遞歸刪除 
	if(L==NULL)
		return ;
	if(L->data==x){				 
		p=L;					//讓p指向了數據域與x相等的節點 
		L=L->next;				//指向值爲x節點的指針直接指向了下一個節點 
		free(p);				//釋放p節點,這裏並不會斷鏈 
		Delete_x1(L,x);
	}
	else
		Delete_x1(L->next,x);
}
void Delete_x2(LinkList &L,int x){		//非遞歸方法 
	LinkList p,q;
	LinkList pre;
	pre=(LinkList)malloc(sizeof(LNode));
	while(L->data==x){
		q=L;
		L=L->next;
		free(q);
	}
	p=L;
	pre->next=p;						//創建pre作爲p的前驅指針 
	while(p!=NULL){
		if(p->data==x){	
			q=p;				
			pre->next=p->next;
			p=pre->next;
			free(q);
		}
		else{
			pre=p;
			p=p->next;
		}
	}
	return ;
}

int  main()
{
	int n;
	LinkList L;
	while(true){
		InitList(L);
		cin >> n;
		ListInsert_Tail(L,n); 
		TraveList(L);
		int x;
		cin >> x;
		Delete_x2(L,x);
		TraveList(L);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章