單鏈表刪除元素時,可以按序號刪除,也可以按數據刪除。
這裏寫的是,不帶頭結點的單鏈表的按數據刪除節點。
首先遞歸方式:
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;
}