单链表插入删除元素

单链表,实验内容

(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)上的元素,实现表删除的操作。

常见错误:

  1. 类型定义错误 :应该使用 LinkList 类型,它是链表定义的类型。

  2. 变量未声明 :在 ListInsert_LListDelete_L 函数中,使用 js 变量要声明。

  3. 函数参数类型不匹配ListPrint 函数的参数应该是 LinkList 而不是 LinkList &,因为不需要修改传入的链表头指针。

  4. 引用传递问题 :在 main 函数中,应该首先创建一个链表的头节点,并将其 next 指针设置为 NULL

  5. ElemType 传递方式 :在 GetElem_L 函数中,不能使用 ElemType &e,这在 C 语言中是不合法的。C 语言不支持引用传递,应该使用指针。

  6. 代码风格 :在 C 语言中,通常不使用 & 符号来引用结构体成员,除非是在定义结构体指针。

调试遇到的问题及分析解决方法

  1. 问题 :在 GetElem_L 函数中,循环条件 while(p&&j<1) 永远不会执行,因为 j 初始化为 1,而条件是 j<1
    • 解决方法 :将循环条件改为 while(p && j < i),确保在找到第 i 个元素之前循环继续执行。
  2. 问题 :在 ListInsert_L 函数中,当 i 等于链表长度加 1 时,应该能够成功插入新元素到链表末尾,但原代码中的 if(!p||j>i-1) 阻止了这种情况。
    • 解决方法 :将条件改为 if(!p || j != i-1),这样当 p 为空或 j 不等于 i-1 时才返回错误。
  3. 问题 :在 ListDelete_L 函数中,当 i 等于链表长度时,应该返回错误,因为不存在第 i 个元素。但原代码中的条件 if(!(p->next)||j>i-1) 允许 i 等于链表长度时执行删除操作(尽管实际上不会删除任何元素,因为 p->next 为空)。
    • 解决方法 :虽然这个特定情况可能不会导致错误(因为 p->next 为空时不会执行删除操作),但为了代码的清晰性和一致性,可以保留这个条件检查,或者更明确地处理这种情况。
  4. 问题 :在 main 函数中,插入元素时索引从 1 开始,但链表长度是 0(因为只有一个头结点且其 next 为空),所以第一个元素应该插入到位置 1 而不是 0。
    • 解决方法 :这个问题实际上在代码中已经正确处理了,因为插入函数 ListInsert_L 的索引是从 1 开始的。
  5. 代码风格 :使用 ElemType &e 作为函数参数时,需要注意在函数内部直接通过 e 赋值,而在调用时不需要额外的 & 符号(除非是在需要指针的场景下)。
    • 解决方法 :在 ListDelete_LGetElem_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;  
}
相关推荐
不去幼儿园35 分钟前
【MARL】深入理解多智能体近端策略优化(MAPPO)算法与调参
人工智能·python·算法·机器学习·强化学习
Mr_Xuhhh37 分钟前
重生之我在学环境变量
linux·运维·服务器·前端·chrome·算法
盼海2 小时前
排序算法(五)--归并排序
数据结构·算法·排序算法
网易独家音乐人Mike Zhou5 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
向宇it7 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
九鼎科技-Leo8 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
搬砖的小码农_Sky8 小时前
C语言:数组
c语言·数据结构
Heaphaestus,RC9 小时前
【Unity3D】获取 GameObject 的完整层级结构
unity·c#
Swift社区9 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
baivfhpwxf20239 小时前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#