PTA:从单链表 list 中删除第 i 个元素
请编写程序,将 n 个整数顺次插入一个初始为空的单链表的表头。随后对任意给定的位序 i,删除链表中第 i 个结点。注意:i 代表位序,从 1 开始。删除结束后,输出链表长度,并顺序输出链表中的每个结点的数值。
输入格式:
输入首先在第一行给出正整数 n(≤104);随后一行给出 n 个 int 范围内的整数,数字间以空格分隔;最后一行给出删除位序 i,为 int 范围内的整数。
输出格式:
如果删除的位置不合法,则不能删除,在一行中输出句子 错误:删除位置不合法。。无论是否删除成功,都按照题面描述的要求,在一行中输出链表信息,格式为:
表长: x1 x2 ... xn
注意数字间有 1 个空格分隔,行首尾无多余空格。
输入样例 1:
5
1 2 3 4 5
3
输出样例 1:
4: 5 4 2 1
输入样例 2:
5
4 3 6 8 0
0
输出样例 2:
错误:删除位置不合法。
5: 0 8 6 3 4
代码如下:
#include<iostream>
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
using namespace std;
void CreateList(LinkList &L,int n)
{
L=new LNode;
L->next=NULL;
for(int i=0;i<n;i++)
{
int num;
cin>>num;
LinkList p=new LNode;
p->data=num;
p->next=L->next;
L->next=p;
}
}
int DeleteLNode(LinkList &L,int i)
{
if(i<1)
return 0;
int j=1;
LinkList p=L;
while(p&&j<i)
{
p=p->next;
j++;
}
if(!p||!p->next)
return 0;
LinkList temp=p->next;
p->next=temp->next;
delete temp;
return 1;
}
void PrintLNode(LinkList &L)
{
LinkList p=L->next;
int i=0;
while(p)
{
cout<<" "<<p->data;
p=p->next;
i++;
}
}
int main()
{
LinkList L;
int n;
cin>>n;
CreateList(L,n);
int i;
cin>>i;
if(DeleteLNode(L,i))
{
cout<<n-1<<':';
}else{
cout<<"错误:删除位置不合法。"<<endl;
cout<<n<<":";
}
PrintLNode(L);
cout<<endl;
return 0;
}
做题小结:
1、在删除链表节点时,我们需要修改被删除节点的前驱节点的 next 指针。使用 p = L 可以让指针 p 遍历到要删除节点的前驱节点,从而顺利完成删除操作;而使用 p = L->next 会使指针直接指向第一个实际节点,在删除非第一个节点时,无法找到其前驱节点,导致无法完成删除操作。
2、p = L 的使用情况 :
1)遍历链表并访问每个节点(包括头节点):当需要对链表进行全面遍历,且要处理头节点以及后续所有节点的情况时,会使用 p = L。例如,打印链表所有节点的信息,包括头节点中可能存储的一些链表相关的元数据(如链表长度等),就需要从 L 开始遍历。
2)在链表头部插入节点:要在链表头部插入新节点,需要先将 p 指向头节点 L,然后通过修改 L 的 next 指针来插入新节点,使其成为链表的新第一个实际节点。
3)删除链表中的节点(需要找到前驱节点):在删除链表中任意位置的节点时,为了能够找到要删除节点的前驱节点,以便修改前驱节点的 next 指针来完成删除操作,需要从 p = L 开始遍历链表,直到找到前驱节点。
3、 p = L->next 的使用情况 :
1)遍历链表中的实际数据节点(不考虑头节点):如果确定不需要处理头节点,只关注链表中存储实际数据的节点,那么可以使用 p = L->next 来跳过头节点,直接从第一个实际数据节点开始遍历。例如,当链表的头节点仅用于存储链表的一些管理信息(如链表长度、链表类型标识等),而不存储实际数据时,遍历实际数据节点就可以从 L->next 开始。
2)查找特定数据节点(已知不在头节点中):当明确要查找的数据节点不会存储在头节点中,且链表有头节点时,可以从 p = L->next 开始查找,这样可以提高查找效率,减少不必要的比较操作。
更多推荐



所有评论(0)