单链表删除元素时,可以按序号删除,也可以按数据删除。
这里写的是,不带头结点的单链表的按数据删除节点。
首先递归方式:
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;
}