【数据结构】二、线性表:2.单链表的插入、删除、查找

2.3插入
2.3.1按位序插入

ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。

  1. 带头结点

把头结点看作第0个结点,位置 i 就是 i-1 个结点

//在第i个位置插插入元素e(带头结点)
bool ListInsert(LinkList &L, int i, ElemType e){
    if(i<1)		//位序1是头结点
        return false;
    LNode *p;	//指针p指向当前扫描到的结点
    int j=0;	//当前p指向的是第几个结点
    p = L;		//L指向头结点,头结点是第0个结点(不存数据)
    
    //循环找到第 i-1 个結点,p是前一个结点,插入p的后面
    while (p!=NULL && j<i-1) {
        p=p->next;
        j++;
    }
    
    if(p==NULL)		//i值不合法
        return false;
    
    LNode *s = (LNode *)malloc(sizeof(LNode));//新结点
    s->data = e;
    s->next = p->next;
    p->next = s;	//将结点s连到p之后
    return true;	//插入成功
}

请添加图片描述
有一个while所以时间复杂度是O(n)

  1. 不带头结点
bool ListInsert(LinkList &L, int i, ElemType e){ 
    if(i<1)
        return false;
    if(i==1){ 	//插入第1个结点的操作与其他结点操作不同
        LNode *s = (LNode *) malloc(sizeof(LNode));
        s->data = e;
        s->next = L;
        L=s;	//头指针指向新结点
        return true;
    }
    LNode *p;	//指针p指向当前扫描到的结点
    int j=1;	//当前p指向的是第几个结点
    p=L;		//p指向第1个结点(注意:不是头结点)
    
    //循环找到第 i-1 个結点,p是前一个结点,插入p的后面
    while (p!=NULL && j<i-1) { 
        p=p->next;
        j++;
    }
    
    if(p==NULL)	//i值不合法
        return false;
    LNode *s = (LNode *) malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;//插入成功
}
2.3.2指定结点后插入

InsertNextNode(LNode *p, ElemType e)

//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p, ElemType e){
    if (p==NULL)
        return false;
    LNode *s = (LNode *)malloc(sizeof(LNode));
    if (s==NULL)	//内存分配失败
        return false;
    s->data = e;		//用结点s保存数据元素e
    s->next = p->next;
    p->next = s;		//将结点s连到p之后
    return true;
}

时间复杂度O(1)

2.3.3指定结点前插入

InsertPriorNode(LNode *p, ElemType e)

//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p, ElemType e){
    if (p==NULL)
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	if (s==NULL)	//内存分配失败
		return false;
    //
	s->next = p->next;
	p->next = s;	//新结点s连到p之后
	s->data = p->data;	//将p中元素复制到s中
	p->data = e;	//p中元素覆盖为e
    return true;
}

转移p结点的内容到后面,在逻辑上实现在p结点前插入。

原链表
删除
p,现在内容是新的e
...etc
p-next
...
新结点s,内容是之前p结点的内容

时间复杂度O(1)

前插操作:在p结点之前插入结点 s(王道书版本)

//前插操作:在p结点之前插入结点s
bool InsertPriorNode(LNode *p, LNode *s){
    if (p==NULL || s==NULL)
        return false;
    s->next = p->next;
    p->next = s;	//s连到p之后
    //交换数据域部分
    ElemType temp = p->data;
    p->data = s->data;
    s->data = temp;
    return true;
}
2.4删除
2.4.1按位序删除

ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。

//按位序删除(带头结点)
bool ListDelete(LinkList &L,int i,ElemType e){
    if(i<1)B
    	return false;
    LNode *p;	//指针p指向当前扫描到的结点
    int j = 0;	//当前p指向的是第几个结点
    p = L;		//L指向头结点,头结点是第0个结点(不存数据)
    //循环找到第 i-1 个结点
    while(p!=NULL && j<i-1){
        p=p->next;
        j++;
    }
    
    if(p==NULL)	//i值不合法
        return false;
    LNode *q = p->next;	//令q指向被删除结点(拿到结点),也就是p->next
    e = q->data;		//用e返回元素的值
    p->next = q->next;	//将*q结点从链中“断开”
    free(q);			//释放结点的存储空间
    return true;		//删除成功
}

例图:

原链表
等价
传递给
删除
删除
p
...etc
p-next,q
...
新结点q,释放空间
返回值e

时间复杂度:O(n)

2.4.2指定结点删除

DeleteNode(LNode * p)

//删除指定结点p
bool DeleteNode(LNode * p)
{
	if (p == NULL)		//若删除的节点为空结点,操作无效
		return false;
	LNode *q = p->next;	//定义一个q指针,令q指向*p的后继结点
	p->data = p->next->data;//和后继结点交换数据域,相当于将p节点的后一个结点的数据赋值到p结点中
	p->next = q->next;    	//将*q结点从链中“断开” 
	free(q);            	//释放后继结点的存储空间
	return true;
}

时间复杂度:O(1)

由于需删除结点的前驱结点未知,或者要删除的是第一个结点,且不带头结点。那么换个思路,创建一个q指针指向p结点的后继结点,将p结点的后继结点q中的数据覆盖到p结点数据域中,然后令p结点指向q结点的后继结点: p->next = q->next;再删掉“悬空”的q结点完成操作。

等同于:1->2->3->4,若要删掉1,可以先令前两个数据交换,2->1->3->4,再让1的指针链断开,令2指向3: 2->(1)-3->4, 把1断开,于是就是2->3->4。

注意:如果要删除的p结点是最后一个结点,以上偷天换日法无法使用,我们只能从表头开始依次往后寻找p的前驱,时间复杂度为O(n)。

2.5查找
2.5.1按位查找

GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值。

单链表按位查找是指根据节点在链表中的位置(即节点序号或下标)来查找节点的操作。通常情况下,我们需要查找的节点序号是从1开始计数的,即第1个节点、第2个节点、第3个节点等。基本思路是从链表头节点开始,遍历链表,直到找到第k个节点,或者链表遍历结束。如果链表遍历结束仍未找到第k个节点,则返回空指针。

//按位查找
LNode* GetElem(LinkList L, int i)
{
	if(i < 0)		//判断i是否合法
		return NULL;
	LNode *p;		//指针p指向当前扫描到的结点
	int j=0;		//当前p指向的是第几个结点
	p=L;			//L指向头结点,头结点是第0个结点(不存数据)
	while(p!=NULL && j<i){	//寻找第i个结点
		p=p->next;	//让p指针依次往后移
		j++;
	}
	return p;
}

王道书版:

LNode* GetElem(LinkList L, int i){
    int j=1;
    LNode *p=L->next;
    
    if(i==0)	//特殊情况是头结点
        return L;
    if(i<1)		//小于1的结点不合法
        return NULL;
    
    while(p!=NULL && j<i){
        p=p->next;
        j++;
    }
    return p;
}

时间复杂度:O(n)

请添加图片描述

2.5.2按值查找

LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素。

  • 单链表查找需要遍历整个链表,时间复杂度为 O(n),其中 n 是链表节点的个数。
  • 当链表为空时,需要特别处理。
  • 如果目标值在链表中不存在,可能需要额外处理,比如返回一个空指针,或者打印出 “Not Found” 等提示信息。
  • 需要根据具体问题和代码实现,特别注意链表头节点指针的正确性,以及节点指针的移动和连接等操作。
//按值查找, 找到数据域 ==e 的结点
LNode* LocateElem(LinkList L, ElemType e) {
	LNode *p = L->next;
	//从第1个结点开始查找数据域为e的结点
	while(p != NULL && p->data != e)
		p = p->next;
	return p;    //找到后返回该结点指针,否则返回NULL
}

时间复杂度为:O(n)

  • 29
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线性实验报告 实验的目的要求 了解线性的逻辑结构特性,以及这种结构特性在计算机内的两种存储结构。 掌握线性的顺序存储结构的定义及其C语言实现。 掌握线性的链式存储结构——链表的定义及其C语言实现。 掌握线性在顺序存储结构即顺序中的各种基本操作。 掌握线性在链式存储结构——链表中的各种基本操作。 6、认真阅读和掌握实验的程序。 7、上机运行本程序。 8、保存和打印出程序的运行结果,并结合程序进行分析。 二、 实验的主要内容 题目: 请编制C语言,利用链式存储方式来实现线性的创建、插入删除查找等操作。 具体地说,就是要根据键盘输入的数据建立一个链表,并输出该链表;然后根据屏 幕 菜的选择,可以进行数据的插入删除,并在插入删除数据后,再输出链表;最 后 在屏幕菜中选择0,即可结束程序的运行。 三、 解题思路分析 在链表插入数据,不需要进行大量的数据移动,只需要找到插入点即可,可以采用后 插入的算法,在插入点的后面添加结点。在链表删除数据,先找到删除点,然后进行 指针赋值操作。 四、程序清 #include<stdio.h> #include<stdlib.h> #include<math.h> typedef int ElemType; typedef struct LNode {ElemType data; struct LNode *next; }LNode; LNode *L; LNode *creat_L(); void out_L(LNode *L); void insert_L(LNode *L,int i,ElemType e); ElemType delete_L(LNode *L,ElemType e); int locat_L(LNode *L,ElemType e); void main() {int i,k,loc; ElemType e,x; char ch; do{printf("\n"); printf("\n 1.建立链表"); printf("\n 2.插入元素"); printf("\n 3.删除元素"); printf("\n 4.查找元素"); printf("\n 0.结束程序运行"); printf("\n================================"); printf("\n 请输入您的选择(1,2,3,4,0)"); scanf("%d",&k); switch(k) {case 1:{L=creat_L(); out_L(L); }break; case 2:{printf("\n请输入插入位置:"); scanf("%d",&i); printf("\n请输入要插入元素的值:"); scanf("%d",&e); insert_L(L,i,e); out_L(L); }break; case 3:{printf("\n请输入要删除元素的位置:"); scanf("%d",&i); x=delete_L(L,i); out_L(L); if(x!=-1) {printf("\n删除的元素为:%d\n",x); printf("删除%d后的链表为:\n",x); out_L(L); } else printf("\n要删除的元素不存在!"); }break; case 4:{printf("\n请输入要查找的元素值:"); scanf("%d",&e); loc=locat_L(L,e); if(loc==-1)printf("\n为找到指定元素!"); else printf("\n已找到,元素位置是%d",loc); }break; } printf("\n----------------"); }while(k>=1&&k<5); printf("\n 按回车键,返回...\n"); ch=getchar(); } LNode *creat_L() { LNode *h,*p,*s; ElemType x; h=(LNode *)malloc(sizeof(LNode)); h->next=NULL; p=h; printf("\n请输入第一个数据元素:"); scanf("%d",&x); while(x!=-999) {s= (LNode *)malloc(sizeof(LNode)); s->data=x; s->next=NULL; p->next=s; p=s; printf("请输入下一个数据:(输入-999示结束.)"); scanf("%d",&x); } return(h); } void out_L(LNode*L) { LNode*p; p=L->next; printf("\n\n");

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值