单链表,实验内容
(1)分别建立4个元素的线性表L={2,3,4,5}
(2)在L={2,3,4,5}的元素4与5之间插入一个元素9,实现表插入的基本操作,
(3)在L={2,3,4,9,5}中删除指定位置(i=3)上的元素,实现表删除的操作。
常见错误:
-
类型定义错误 :应该使用
LinkList
类型,它是链表定义的类型。 -
变量未声明 :在
ListInsert_L
和ListDelete_L
函数中,使用j
和s
变量要声明。 -
函数参数类型不匹配 :
ListPrint
函数的参数应该是LinkList
而不是LinkList &
,因为不需要修改传入的链表头指针。 -
引用传递问题 :在
main
函数中,应该首先创建一个链表的头节点,并将其next
指针设置为NULL
。 -
ElemType
传递方式 :在GetElem_L
函数中,不能使用ElemType &e
,这在 C 语言中是不合法的。C 语言不支持引用传递,应该使用指针。 -
代码风格 :在 C 语言中,通常不使用
&
符号来引用结构体成员,除非是在定义结构体指针。
调试遇到的问题及分析解决方法
- 问题 :在
GetElem_L
函数中,循环条件while(p&&j<1)
永远不会执行,因为j
初始化为 1,而条件是j<1
。- 解决方法 :将循环条件改为
while(p && j < i)
,确保在找到第i
个元素之前循环继续执行。
- 解决方法 :将循环条件改为
- 问题 :在
ListInsert_L
函数中,当i
等于链表长度加 1 时,应该能够成功插入新元素到链表末尾,但原代码中的if(!p||j>i-1)
阻止了这种情况。- 解决方法 :将条件改为
if(!p || j != i-1)
,这样当p
为空或j
不等于i-1
时才返回错误。
- 解决方法 :将条件改为
- 问题 :在
ListDelete_L
函数中,当i
等于链表长度时,应该返回错误,因为不存在第i
个元素。但原代码中的条件if(!(p->next)||j>i-1)
允许i
等于链表长度时执行删除操作(尽管实际上不会删除任何元素,因为p->next
为空)。- 解决方法 :虽然这个特定情况可能不会导致错误(因为
p->next
为空时不会执行删除操作),但为了代码的清晰性和一致性,可以保留这个条件检查,或者更明确地处理这种情况。
- 解决方法 :虽然这个特定情况可能不会导致错误(因为
- 问题 :在
main
函数中,插入元素时索引从 1 开始,但链表长度是 0(因为只有一个头结点且其next
为空),所以第一个元素应该插入到位置 1 而不是 0。- 解决方法 :这个问题实际上在代码中已经正确处理了,因为插入函数
ListInsert_L
的索引是从 1 开始的。
- 解决方法 :这个问题实际上在代码中已经正确处理了,因为插入函数
- 代码风格 :使用
ElemType &e
作为函数参数时,需要注意在函数内部直接通过e
赋值,而在调用时不需要额外的&
符号(除非是在需要指针的场景下)。- 解决方法 :在
ListDelete_L
和GetElem_L
函数中,使用ElemType &e
是正确的,因为这样可以避免不必要的内存分配和复制操作。在调用这些函数时,直接传递变量名即可。
- 解决方法 :在
cs
#define ERROR 0
#define OK 1
#define OVERFLOW -2
#include <stdio.h>
#include <stdlib.h> //引入stdlib.h以使用malloc和realloc
typedef int ElemType; //定义ElemType为数据元素类型
typedef int Status; //Status是变量的类型,其值是函数结果状态代码
typedef struct LNode{
ElemType data; //结点值
struct LNode *next; //连接下一个结点的地址
}LNode,*LinkList; //数据域,指针域
Status GetElem_L(LinkList L,int i,ElemType &e){
//这里用ElemType &e则下面用 e=p->data;若为*e则下面也要*e
//L为带头结点的单链表的头指针
//当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
LNode *p=L->next;
int j=1; //初始化,p指向第一个结点,j为计数器
while(p&&j<i){ //顺时针向后查找,直到p指向第i个元素或p为空
p=p->next;
++j;
}
if(!p||j>1)return ERROR; //第i个元素不存在
e=p->data; //取第i个元素
return OK;
}//GetElem_L
Status ListInsert_L(LinkList *L,int i,ElemType e){
//存疑,这里用 LinkList *L,则下面用LNode *p=*L而非p=L ,同时定义*s
//在带头结点的单链线性表L中第i个位置之前插入元素e
LNode *p=*L,*s;
int j=0;
while(p&&j<i-1){
p=p->next;
++j;
} //寻找第i-1个结点
if(!p||j>i-1)return ERROR; //i<1或者大于表长+1
s=(LinkList)malloc(sizeof(LNode)); //生成新节点
s->data=e;
s->next=p->next; //插入L中
p->next=s;
return OK;
}//ListInsert_L
Status ListDelete_L(LinkList *L,int i,ElemType &e){ //同上
//在带头结点的单链线性表L中,删除第i个元素,并由e返回其值
LNode *p=*L,*q;
int j=0;
while(p->next&&j<i-1){ //寻找第i个结点,并令p指向其前驱
p=p->next;++j;
}
if(!(p->next)||j>i-1)return ERROR; //删除位置不合理
q=p->next;
p->next=q->next; //删除并释放结点
e=q->data; free(q);
return OK;
}//ListDelete_L
void ListPrint(LinkList L){
LNode *temp=L->next; //从头结点的下一个结点开始打印
while(temp!=NULL){
printf("%d ",temp->data);
temp=temp->next;
}
printf("\n");
}
int main() {
LinkList L=(LinkList)malloc(sizeof(LNode)); //创建头结点
if(!L) return -1; //内存分配失败
L->next=NULL; //初始化头结点的next指针
ElemType e;
// 插入元素建立线性表L={2,3,4,5}
for (int i = 1; i <= 4; i++) {
ListInsert_L(&L, i, i + 1);
}
// 打印线性表L
printf("线性表L={");
ListPrint(L);
// 在L={2,3,4,5}的元素4与5之间插入一个元素9
ListInsert_L(&L, 4, 9);
// 打印插入后的线性表L
printf("插入9后,线性表L={");
ListPrint(L);
// 在L={2,3,4,9,5}中删除指定位置(i=3)上的元素
if (ListDelete_L(&L, 3, e)) {
//ListDelete_Sq里用ElemType *e时这里要用&e,若用ElemType &e时这里用e
printf("删除位置i=3的元素,其值为%d\n", e); //删除位置i从1,2,3数起
} else {
printf("删除失败\n");
}
// 打印删除后的线性表L
printf("删除后,线性表L={");
ListPrint(L);
return 0;
}