单链表的删除与插入

单链表的定义

什么是单链表

  • 顺序表:可随机存取,存储密度高;但是要大片连续空间,改变容量不方便
  • 单链表:不要求大片连续空间;但是不可随机存取,要耗费一个空间放指针

用代码定义一个单链表——链表由节点组成

每个结点可以定义为:

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

增加一个新的结点:在内存中申请一个结点所需空间,并用指针P指向这个结点

struct LNode *P = (struct LNode *)malloc(sizeof(struct LNode));

typedef关键字——数据类型重命名
t y p e d e f < 数 据 类 型 > < 别 名 > typedef<数据类型><别名> typedef<><>
typedef struct LNode;

LNode *P = (LNode *)malloc(sizeof(LNode));

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

  • LNode * GetElem(LinkList L,int i){
        int j=1;
        LNode *p=L->next;
        if(i==0)
            return L;
        if(i<1)
            return NULL;
        while(p!=null && j<i){
            p=p->next;
            j++;
        }
        return p;
    }
    

    强调这是一个单链表 ——使用LinkList

    强调这是一个结点 ——使用LNode *

两种实现

不带头结点

#include<stdio.h>
typedef int ElemType;
typedef struct LNode{               //定义单链表结点类型
    ElemType data;         //每个结点存放一个数据元素
    struct LNode *next;     //指针指向下一个结点
}LNode,*LinkList;
//初始化一个空的单链表
bool InitList(LinkList &L){
    L = NULL;   //空表,暂时还没有任何结点,防止脏数据
    return true;
}
int main(){
    //这里的没有创建一个结点
    LinkList L; //申明一个指向单链表的指针
    //初始化一个空表
    printf("%d",L);//打印链表的初始地址
    InitList(L);
    //……后续代码
    return 0;
}

带头结点

#include<stdio.h>
typedef int ElemType;
typedef struct LNode{               //定义单链表结点类型
    ElemType data;         //每个结点存放一个数据元素
    struct LNode *next;     //指针指向下一个结点
}LNode,*LinkList;
//初始化一个空的单链表
bool InitList(LinkList &L){
    L = (LNode *) malloc(sizeof(LNode));
    if(L==NULL)
        return false;
    L->next=NULL;
    return true;
}
int main(){
    //这里的没有创建一个结点
    LinkList L; //申明一个指向单链表的指针
    //初始化一个空表
    printf("%d",L);//打印链表的初始地址
    InitList(L);
    //……后续代码
    return 0;
}

不带头节点,写代码更麻烦,对第一个数据结点和后续数据结点的处理需要用不同的代码逻辑,对空表和非空表的处理需要用不懂的代码逻辑。

单链表插入和删除

带头结点

插入(按位序插入)

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

#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode{               //定义单链表结点类型
    ElemType data;         //每个结点存放一个数据元素
    struct LNode *next;     //指针指向下一个结点
}LNode,*LinkList;
//初始化一个空的单链表
bool InitList(LinkList &L){
    L = (LNode *) malloc(sizeof(LNode));
    if(L==NULL)
        return false;
    L->next=NULL;
    return true;
}
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){
        p=p->next;
        j++;
    }
    if(p==NULL){
        return false;//i值不合法
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    s->data = e;
    //下面的顺序很重要
    s->next = p->next;
    p->next = s;
    return true;
}

删除(按位序删除)

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

不带头结点

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){
        p=p->next;
        j++;
    }
     if(p==NULL){
        return false;//i值不合法
    }
    if(p->next == NULL){//第i-1个结点之后已无其他结点
        return false;
    }
    LNode *q=p->next;   //令q指向被删除结点
    e = q->data;        //用e返回元素的值
    p->next = q->next;  //将*q结点从链中断开
    free(q);            //释放结点的存储空间
    return true;        //删除成功
}

删除指定结点
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(q);                //释放后继结点的存储空间
    return true;
}

插入(按位序插入)

#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode{               //定义单链表结点类型
    ElemType data;         //每个结点存放一个数据元素
    struct LNode *next;     //指针指向下一个结点
}LNode,*LinkList;
//初始化一个空的单链表
bool InitList(LinkList &L){
    L = (LNode *) malloc(sizeof(LNode));
    if(L==NULL)
        return false;
    L->next=NULL;
    return true;
}
bool ListInsert(LinkList &L,int i,ElemType e){
    if(i<1)
        return false;
    if(i==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;        //L指向头结点,头结点是第0个结点(不存数据)
    while(p!=NULL && j<i-1){
        p=p->next;
        j++;
    }
    if(p==NULL){
        return false;//i值不合法
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    s->data = e;
    //下面的顺序很重要
    s->next = p->next;
    p->next = s;
    return true;
}
插入(按指定结点后面插入)
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode{               //定义单链表结点类型
    ElemType data;         //每个结点存放一个数据元素
    struct LNode *next;     //指针指向下一个结点
}LNode,*LinkList;
//初始化一个空的单链表
bool InitList(LinkList &L){
    L = (LNode *) malloc(sizeof(LNode));
    if(L==NULL)
        return false;
    L->next=NULL;
    return true;
}
bool ListInsert(LinkList &L,int i,ElemType e){
    if(i<1)
        return false;
    if(i==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;        //L指向头结点,头结点是第0个结点(不存数据)
    while(p!=NULL && j<i-1){
        p=p->next;
        j++;
    }
    return InsertNextNode(p,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;
    return true;
}
插入(按指定结点前面插入)
bool InsertPrioNode(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->data = p->data;
    p->data =e;
    return true;
}

注:新声明一个结点,先插入结点的后面,再把结点的值赋值给新节点,再把插入的值给原来的节点就实现插入到前面了(先连到后面再换值)

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值