关于单链表一些基本操作的另一些代码实现

本文详细介绍了单链表的插入与删除操作,包括按位序插入(带头结点和不带头结点)以及按位序删除。在带头结点的链表中,插入操作从头结点开始,找到第i-1个结点后插入新节点;删除操作则通过找到第i-1个结点,将其next指向第i+1个结点。对于不带头结点的链表,插入第1个结点时需要更新头指针。此外,还讨论了指定结点的前插与删除操作,以及相应的代码实现。
摘要由CSDN通过智能技术生成

 按位序插入(带头结点)

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

我们采用的方式是找到第i-1个结点,将新的结点插入其后。只需将i-1结点的next的指针指向新的结点,然后再让新的结点的next指针指向第i个结点。

 如图所示,可看出这个是一个有头结点的单链表,在外面在a1结点的前面插入元素时,可以把头结点看做是第0个结点,在头结点之后实现上述操作。而没有头结点的单链表要实现这个操作相对而言就比较麻烦了。

代码实现:

typedef struct LNode{             //定义单链表结点类型
   ElemType data;                 //每个结点存放一个数据元素
   struct LNode *next;            //指针指向下一个结点
}LNode,*LinkList;

bool ListInsert(LinkList &L,int i ,ElemType e)
  if(i<1)
    return false;
  LNode *p;                       //指针p指向当前扫描到的结点
  int j =0;                       //当前p指向的是第几个结点
  p=L;                            //L指向的头结点,头结点是第0个结点(不存储数据)
  while (p!=NULL && j<i-1){  //循环找到第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 ture;      //插入成功

按位序插入(不带头结点)

不带头结点的单链表与都头结点的单链表除了第一个结点之前插入元素与之不同外,之后的结点的插入是相同的方法,在插入删除第1个元素时,需要更改头指针L。

typedef struct LNode{             //定义单链表结点类型
   ElemType data;                 //每个结点存放一个数据元素
   struct LNode *next;            //指针指向下一个结点
}LNode,*LinkList;

bool ListInsert(LinkList &L,int i ,ElemType e)
  if(i<1)
    return false;
if(i==1)
{
LNode 8s = (LNode *) malloc(sizeof(LNode));
s->data = e;
s=>next=L;
L=s;   //头指针指向新的结点
return ture;
}
  LNode *p;                       //指针p指向当前扫描到的结点
  int j =1;                       //当前p指向的是第几个结点
  p=L;                            //L指向的头结点,头结点是第0个结点(不存储数据)
  while (p!=NULL && j<i-1){  //循环找到第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 ture;      //插入成功

不难发现,不抬头结点的单链表在i=1时进行了特殊处理,相对于不带头结点的单链表就麻烦了许多。

单链表的删除操作

指定结点的前插操作

当给定一个结点--p,我们可以用循环的方式来寻找后面的结点来实现插入操作,但是如果连头指针也不知道的情况下,p之前的结点我们就无从得知了,那如何实现结点的前操作呢?

 bool InsertpriorNode (LNode *p, ElemType e)

假设我们在表中第i个结点之前插入一个结点e,我们可以先在第i个结点的后面插入一个data里没有数据的空结点,然后把第i个结点里的值传给新插入的结点里,然后再把插入结点e的值换到原本第i个结点里,就实现了结点的前插操作。

代码实现:

bool InsertPriorNode (LNode *p,ElemType e){
  if (p==NULL)
     return false;
LMode *s = (LNode *)malloc(sizeof(LNode));
id(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 ture;
}

 按位序删除(带头结点)

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

我们可以找到第i-1个结点将他的指针指向第i+1个结点,然后再释放(删除)第i个结点、

头结点可以看做是第0个结点在操作。

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

指定结点的删除

当我们不知道头指针时候,假设我们要删除第i个结点,那么就把第i+1个结点元素的值给复制给要删除的元素也就是第i个结点里,然后让第i个结点的next指针指向第i+2个结点,之后再释放掉第i+1个结点的空间,这样就实现了对第i个结点的删除操作。

代码实现:

bool DeleteNode (LNode *p){
  if (p==NULL)
     return false;
LNode *q=p->next;           //令q指向*p的后续结点
p->data=p->next->data;      //和后续结点交换数据域
p-<next=q->next;            //将*q结点从链中断开
free(p);                    //释放后继续结点的储存空间
return ture;
}

上述代码有个问题就是当要删除的p结点刚好是最后一个结点时,他的next指针指向的是一个NULL空指针,那么上述的第5行操作就会出错,当我们对最后一个结点进行释放时候,上一个结点的next指针就会成为野指针。所以,我们应该判断一下,假如是最后一个的话,就把上一个结点的next指针设置为NULL空指针。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chihiro1122

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值