1、设计一个递归算法,删除不带头节点的单链表L中所有值为x的结点
void Del_X_3(LinkList &L,ElemType x)
{
LNode *p;
if(L=null)
return ;
if(L->data==x)
{
p=L;
L=L->next;
free(p);
Del_X_3(L,x);
}else{
Del_X_3(L->next,x);
}
}
2、在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,假设值为x的结点不唯一,试编写算法以实现上述操作
方法1
void Del_X_3(LinkList &L,ElemType x)
{
LNode *p=L->next,*pre=L,*q;
while(p!=null)
{
if(p->data==x)
{
q=p;
p=p->next;
pre->next=p;
free(q);
}else{
pre=p;
p=p->next;
}
}
}
方法2
void Del_X_3(LinkList &L,ElemType x)
{
LNode *p=L->next,*r=L,*q;
while(p!=null)
{
if(p->data!=x)
{
r->next=p;
r=p;
p=p->next;
}else{
q=p;
p=p->next;
free(q);
}
}
}
3、设L为带头节点的单链表,编写算法实现从尾到头反向输出每个结点的值
void R_Print(LinkList L)
{
if(L->next != null)
{
R_Print(L->next);
}
printf(L->data);
}
一、带头结点和不带头结点的区别:
1、不带头结点的单链表对于第一个节点的操作与其他节点不一样,需要特殊处理,这增加了程序的复杂性和出现bug的机会,因此,通常在单链表的开始结点之前附设一个头结点。
2、带头结点的单链表,初始时一定返回的是指向头结点的地址,所以一定要用二维指针,否则将导致内存访问失败或异常。
3、带头结点与不带头结点初始化、插入、删除、输出操作都不样,在遍历输出链表数据时,带头结点的判断条件是while(head->next!=NULL), 而不带头结点是while(head!=NULL),虽然头指针可以在初始时设定,但是如1所述,对于特殊情况如只有一个节点会出现问题。
二、头结点作用
- 头结点是为了操作的统一与方便而设立的,放在第一个元素结点之前,其数据域一般无意义(当然有些情况下也可存放链表的长度、用做监视哨等等)。
- 有了头结点后,对在第一个元素结点前插入结点和删除第一个结点,其操作与对其它结点的操作统一了。
- 首元结点也就是第一个元素的结点,它是头结点后边的第一个结点。头结点不是链表所必需的。