2.3 单链表及其基本操作

目录

1.头文件

2.定义

3.初始化

(1)不带头结点

(2)带头结点

4.判空

(1)不带头结点

(2)带头结点

5.按位插入

(1)不带头结点

(2)带头结点

6.后插法

7.前插法

(1)不带头结点

(2)带头结点

8.删除

(1)删除指定结点

(2)按位删除

9.查找

(1)按位查找

(2)按值查找

10.求表长

11.建立单链表

(1)头插法

(2)尾插法

12.顺序表的逆置

13.单链表的打印

14.主函数


1.头文件

#include <string.h>
#include <cstdio>
#include <cstdlib>

2.定义

//单链表的定义
typedef struct LNode{    //定义单链表结点类型
    int data;       //每个节点存放一个整型元素
    struct LNode *next;  //指针指向下一个节点
}LNode,*LinkList;
//重命名等价于
// typedef struct LNode LNode; # typedf <原名字> <别名>
// typedef struct LNode *LinkList;
// LNode *L==LinkList L  ->声明一个指向单链表第一个结点的指针(头指针)
// 强调这是一个单链表 LinkList  强调这是一个结点  LNode *

3.初始化

(1)不带头结点

// 不带头节点的单链表初始化
bool InitList_nohead(LinkList &L){
    L=NULL;
    return true;
}

(2)带头结点

//带头结点初始化
bool InitList(LinkList &L){
    L = (LNode *) malloc(sizeof(LNode));//申请一片空间,让头指针指向它
    if(L==NULL){  //内存不足,则分配失败
        return false;}
    L->next=NULL;//头指针指向的结点的指针域指向NULL,因为此时还没有下一个结点
    return true;
}

4.判空

(1)不带头结点

//判断不带头节点空链表是否为空
bool Empty_nohead(LinkList L) {
    if (L == NULL) {
        printf("该表为空!\n");
        return true;
    } else {
        printf("该表非空!\n");
        return false;}
}

(2)带头结点

//判断带头节点的单链表是否为空
bool Empty(LinkList L){
    if(L->next == NULL){
        printf("该单链表为空!\n");
        return true;
        } else{
        printf("该单链表非空!\n");
        return false;}
    }

5.按位插入

(1)不带头结点

//按位插入 (不带头结点)
bool ListInsert_nohead(LinkList &L,int i,int e){
    LNode *p;//定义一个指针p指向当前扫到的结点
    p=L;
    if(i<1){
        printf("i<1\n");
        return false;
    } else if(i==1){
        LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
        if(s==NULL){//内存分配失败
            return false;}
        s->data=e;//把要插入的元素值放到结点中
        s->next=L;//把新节点的next指针指向头指针
        L=s;//把头指针指向新节点
        printf("插入成功!\n");
        return true;
    }else {
    int j=1;//定义一个变量j反应当前指向第几个结点
    //p=L;
    while (p!=NULL&&j<i-1){//循环找到第i-1个结点,即要插入的位置的前一位
        //p不指向NULL(即空值)或0结点时
        p=p->next;//p移向p的next结点
        j++;}
    LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
    s->data=e;//把要插入的元素值放到结点中
    s->next=p->next;//把新节点的next指针指向头指针
    p->next=s;//把头指针指向新节点
    printf("插入成功了!\n");
    return true;}
}

(2)带头结点

//按位插入 带头节点
//时间复杂度:最好O(1),最差O(n),平均O(n)
//119-125行可以用LNode *p = GetElem(L,i-1);封装
bool ListInsert(LinkList &L,int i,int e){
    if(i<1){//判断位置i是否合理
        return false;}
    LNode *p;//定义一个指针p指向当前扫到的结点
    int j=0;//定义一个变量j反应当前指向第几个结点
    p=L;//初始值 p指向头节点L,即第0个结点
    while (p!=NULL&&j<i-1){//循环找到第i-1个结点,即要插入的位置的前一位
        //p不指向NULL(即空值)或0结点时
        p=p->next;//p移向p的next结点
        j++;}
    if(p==NULL)//i值太大了
        return false;
    LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
    if(s==NULL){//内存分配失败
        return false;}
    s->data=e;//把要插入的元素值放到结点中
    s->next=p->next;//把新节点的next指针指向i-1位的next指针
    p->next=s;//把i-1位的next指针指向新节点
    return true;
//   以上等价于:
    //return InsertNextNode(p,e);
}

6.后插法

//给定一个结点,实现后插操作:在p节点后插入指针e
bool InsertNextNode(LNode *p,int e){
    if(p==NULL){
        return false;
    }
    LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
    if(s==NULL){//内存分配失败
        return false;
    }
    s->data=e;//把要插入的元素值放到结点中
    s->next=p->next;//把新节点的next指针指向i-1位的next指针
    p->next=s;//把i-1位的next指针指向新节点
    return true;
}

7.前插法

(1)不带头结点

//前插法之无头指针
//时间复杂度O(1)
bool InsertPriorNode_nohead(LNode *p,int e){
    //本质是后插,但移动data
    if(p==NULL){
        return false;}
    LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
    if(s==NULL){//内存分配失败
        return false;}
    s->data=p->data;
    s->next=p->next;
    p->data=e;
    p->next=s;
    return true;
}

(2)带头结点

//给定一个结点,实现前插操作:在p节点前插入指针e
//时间复杂度:O(n)
bool InsertPriorNode(LinkList L,LNode *p,int e){//单链表不可逆所以要传入头指针
    if(p==NULL){
        return false;
    }
    LNode *q;//定义一个指针q指向当前扫到的结点
    int j=0;//定义一个变量j反应当前指向第几个结点
    q=L;//初始值 p指向头节点L,即第0个结点
    while (q!=NULL&&q!=p){//循环找到p前一个结点,即要插入的位置的前一位
        //p不指向NULL(即空值)或p结点时
        p=p->next;//p移向p的next结点
        j++;}
    printf("成功");
    return InsertNextNode(q,e);
    //因为q是p的前一个结点,所以对q后插==对p前插
}

8.删除

(1)删除指定结点

//删除指定结点p  且这个p不能是最后一个结点(此时必须找到p的前驱结点)
//时间复杂度:O(1),如果p是最后一个结点则为O(n)
bool DeleteNode(LNode *p){
    //本质是将p+1的data复制到p,然后删p+1
    if(p==NULL||p->next==NULL){
        return false;
    }
    LNode *q=p->next;//令q指向p+1
    p->data=q->data;//将p+1的值覆盖原p值
    p->next=q->next;//将p的next的指针指向p+2
    free(q);//释放p+1
    return true;
}

(2)按位删除

//按位删除-带头结点
bool ListDelete(LinkList &L,int i) {
    //174-175 179-184行可以用LNode *p = GetElem(L,i-1);封装
    LNode *p;//定义一个指针p指向当前扫到的结点
    p = L;//初始值 p指向头节点L,即第0个结点
    if (i < 1||p==NULL) {//判断位置i是否合理
        return false;
    }
    int j = 0;//定义一个变量j反应当前指向第几个结点
    while (p != NULL && j < i - 1) {//循环找到第i-1个结点,即要插入的位置的前一位
        //p不指向NULL(即空值)或0结点时
        p = p->next;//p移向p的next结点
        j++;
    }
    if(p->next==NULL){//第i-1结点后已无新结点
        return false;}
    LNode *q=p->next;//令q结点指向第i个结点
    p->next=q->next;//令p的next指针指向q的next,即i+1个结点
    int e=q->data;//用变量e接受被删除的值
    free(q);//释放q结点的空间
    printf("被删除的的元素是:%d\n",e);
    return true;
}

9.查找

(1)按位查找

//按位查找 带头结点 返回第i个元素值
//时间复杂度:O(n)
LNode *GetElem(LinkList L,int i){
    LNode *p;//指向当前扫描到的结点
    p=L;//p默认值 指向0结点(头结点)
    if(i<0||p->next==NULL){
        //i不合法(应该在0-实际长度中间)或链表为空 即头结点(不存放数据)next指向空
        printf("该位置没有元素!\n");
        return NULL;
    } else{
        int j=0;//表述当前p指向第几个结点
        while (p!=NULL&&j<1){//当表内有元素时,循环找到第i个结点
            p=p->next;
            j++;
            printf("第%d位元素为:%d\n",i,p->data);
            return p;
        }
    }
}

(2)按值查找

//按值查找 找到数据域等于e的结点
LNode *LocateElem(LinkList L,int e){
    LNode *p=L->next;//将头指针的下一个结点赋值给p,即第一个结点
    while (p->data!=e&&p->next!=NULL){
        p=p->next;//p后移
    }
    return p;
}

10.求表长

//求表长
int Length(LinkList L){
    LNode *p=L;
    int length=0;
    while(p->next!=NULL){
        p=p->next;
        length++;
    }
    printf("该顺序表长度为:%d",length);
    return length;
}

11.建立单链表

(1)头插法

//用头插法建立单链表
LinkList List_HeadInert(LinkList &L,int x){
    LNode *s;
    //int x;//定义一个整型来接收需要插入的函数
    //L=(LinkList) malloc(sizeof(LNode));//建立头结点
    //L->next=NULL;//初始化空表
    //printf("请输入一个数(输入9999退出):");
    //scanf("%d",&x);
    //while (x!=9999){
    s=(LNode *) malloc(sizeof(LNode));
    s->data=x;
    s->next=L->next;
    L->next=s;
        //scanf("%d",&x);
    //}
    return L;
}

(2)尾插法

//用尾插法建立单链表
LinkList List_TailInsert(LinkList &L){//正向声明一个单链表
    int x;//定义一个整型来接收需要插入的函数
    L=(LinkList) malloc(sizeof(LNode));//建立头结点
    LNode *s,*r=L;//r指向尾结点,一开始表为空,所以指向头指针
    printf("请输入一个数(输入9999退出):");
    scanf("%d",&x);
    while (x!=9999){
        s=(LNode *)malloc(sizeof (LNode));//申请一个新结点并由s指向
        s->data=x;//在s的data中存入数据
        r->next=s;//原尾指针于新申请的结点相连
        r=s;//r指向新的尾指针
        scanf("%d",&x);
    }
    r->next=NULL;//尾指针的next为空
    return L;
}

12.顺序表的逆置

//顺序表的逆置
LinkList List_nizhi(LinkList &L){
    LNode *s=L->next;//指向原顺序表的第一个结点
    LinkList p;
    InitList(p);//初始化
    int x=0;//来接收原顺序表中的值
    while(s!=NULL){
        x=s->data;//将该值赋给x
        List_HeadInert(p,x);
        s=s->next;//s后移
    }
    L=p;
    //return p;
}

13.单链表的打印

//单链表的打印
int List_Printf(LinkList L){
    LNode *p=L->next;
    int x=0;
    while (p!=NULL){
        x=p->data;
        p=p->next;
        printf("%d ",x);
    }
    printf("\n");
}

14.主函数

int main() {
    system("chcp 65001");//输出为中文
    LinkList L_nohead;//声明一个指向单链表的指针
    Empty_nohead(L_nohead);//判空
    InitList_nohead(L_nohead);//初始化
    Empty_nohead(L_nohead);//判空
    ListInsert_nohead(L_nohead,1,12);//插入
    ListInsert_nohead(L_nohead,2,13);//插入
    ListInsert_nohead(L_nohead,3,12);//插入
    ListInsert_nohead(L_nohead,4,45);//插入
    //printf("--------测试--------\n");
    //Del_x(L_nohead,12);
    printf("----------------带头结点-----------------\n");
    LinkList L;//声明
    Empty(L);//判空
    InitList(L);//初始化
    Empty(L);//判空
    ListInsert(L,1,12);//插入
    GetElem(L,1);//按位查找
    ListDelete(L,1);//删除
    Empty(L);//判空
    GetElem(L,1);//按位查找
    printf("--------头插法测试--------\n");
    List_HeadInert(L,3);//头插法
    List_HeadInert(L,6);//头插法
    List_Printf(L);//打印
    //printf("--------尾插法测试--------\n");
    //List_TailInsert(L);//尾插法
    //List_Printf(L);//打印
    printf("--------逆置法测试--------\n");
    //L=List_nizhi(L);
    List_nizhi(L);
    List_Printf(L);//打印
    return 0;
}

运行结果:

Active code page: 65001
该表非空!
该表为空!
插入成功!
插入成功了!
插入成功了!
插入成功了!
----------------带头结点-----------------
该单链表为空!
该单链表为空!
第1位元素为:12
被删除的的元素是:12
该单链表为空!
该位置没有元素!
--------头插法测试--------
6 3
--------逆置法测试--------
3 6

进程已结束,退出代码为 0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值