考研数据结构-持续更新

数据结构

一、线性表

1.1、顺序表

  • #include <cstdio>
    #include <cstdlib>
    /*
     * 线性表实现
     */
    
    #define MAXSIZE 100    //定义顺序表能达到的最大长度
    
    typedef int Status;
    typedef int ElemType;
    #define OK 0;
    #define ERROR 1;
    
    /**
     * 定义一个线性表
     */
    typedef struct
    {
        //存储空间的基地址
        ElemType *elem;
        //当前长度
        int length;
        //顺序表的结构类型为sqList
    }SqList;
    
    /**
     * 初始化线性表
     * @param L
     * @return
     */
    Status InitList(SqList &L){
        //给顺序表分配了一个大小为MAXSIZE大小的数组空间
        L.elem = new ElemType[MAXSIZE];
        if (!L.elem){
            //存储分配失败时退出
            exit(0);
        }
        //初始化线性表长度为0
        L.length = 0;
        return OK;
    }
    
    
    /**
     * 取值操作
     * @param L 线性表
     * @param i 取值的位置
     * @param e 取出的值
     * @return
     */
    Status GetElem(SqList L,int i,ElemType &e){
        if (i < 1 || i > L.length){
            //判断 i 的值是否合法
            return ERROR;
        }
        //将取来的值赋值给 e
        e = L.elem[i-1];
        return OK;
    }
    
    /**
     * 查找指定值的元素
     * @param L 顺序表
     * @param e 需要查找的值
     * @return
     */
    int LocateEle(SqList L,ElemType e){
        //在顺序表L中查找值为e的数据元素,并返回去序号
        for (int i = 0;i<L.length;i++){
            //查找成功返回 i +1 ,因为数组的小标是从 0 开始的
            if (L.elem[i] == e){
                return i + 1;
            }
        }
        return 0;
    }
    
    
    /**
     * 插入数据
     * @param L 顺序表
     * @param i 插入的位置
     * @param e 插入的数据
     * @return
     */
    Status ListInsert(SqList &L,int i ,ElemType e){
        //在顺序表L中第i个位置插入新的元素e,i的值的合法范围是 1<=i<=L.length + 1
        if (i < 1 || (i > L.length + 1)){
            //i值不合法
            return ERROR;
        }
        //从后往前替换,遍历到i-1(数组下标是从零开始,而位置是从1开始)这个位置停止,空出要插入的位置
        for (int j = L.length-1;j>=i-1;j--){
            L.elem[j+1] = L.elem[j];
        }
        //插入数据
        L.elem[i-1] = e;
        //长度加一
        ++L.length;
        return OK;
    }
    
    
    /**
     * 删除数据
     * @param L 顺序表
     * @param i 删除的位置
     * @return
     */
    int ListDelete(SqList &L,int i){
        if (i < 1 || (i > L.length+1)){
            return ERROR;
        }
        for (int j = i;j<L.length;j++){
            L.elem[j-1] = L.elem[j];
        }
        --L.length;
        return OK;
    }
    
    
    int main(){
        SqList L;
        InitList(L);
        ElemType num1 = 1;
        ElemType num2 = 2;
        ElemType num3 = 3;
        ListInsert(L,1,num1);
        ListInsert(L,2,num2);
        ListInsert(L,3,num3);
        for (int i = 0;i<L.length;i++){
            printf("%d ",L.elem[i]);
        }
        printf("\n");
        ListDelete(L,2);
        for (int i = 0;i<L.length;i++){
            printf("%d ",L.elem[i]);
        }
        return 0;
    }
    

1.2、链表

1.2.1、链表的插入
  • image-20240518100612048

  • 实例代码

    • /**
       * 插入值
       * @param L 要插入的链表,传入的是地址
       * @param i 插入的位置
       * @param e 插入的值
       * @return
       */
      Status ListInsert(LinkList &L,int i,ElemType e){
          if (i < 1){
              return ERROR;
          }
          //初始化p指向首结点
          LinkList p = L;
          int j = 0;
          //当结点p为null 或者 j = i-1,也就是找到插入位置的前一个结点
          while (p && j < i-1){
              p = p->next;
              ++j;
          }
          //如果p不存在或者j>i-1退出
          if (!p || j > i-1){
              return ERROR;
          }
          //生成一个新结点
          auto s = new LNode;
          //将插入的值赋值给新结点
          s->data = e;
          //将新阶段的指针指向插入位置的后面这个结点
          s->next = p->next;
          //将插入位置前一个结点指向新结点,完成新结点的插入
          p->next = s;
          return OK;
      }
      
1.2.2、删除
  • image-20240518120136573

  • /**
     * 删除结点
     * @param L 传入的是链表的地址
     * @param i 指定删除的位置
     * @return
     */
    Status ListDelete(LinkList &L,int i){
        if (i < 1){
            return ERROR;
        }
        //初始化p指向首结点
        LinkList p = L;
        int j = 0;
        //当结点p的next为null,说明已经到了最后一个结点,说明i不合法 或者 j = i-1,也就是找到删除位置的前一个结点
        while (p->next && j < i-1){
            p = p->next;
            ++j;
        }
        //如果p的下一个结点为null说明遍历到了最后一个结点,表示位置i是不合法的,或者j>i-1退出
        if (!p->next || j > i-1){
            return ERROR;
        }
      //保存删除的结点,以备后续释放内存
      LinkList q = p->next;
      //将删除结点的上一个结点的指针,指向删除结点的下一个节点,也就是跨过删除结点
      p->next = q->next;
      delete q;
      return OK;
    }
    
1.2.3、头插法
  • IMG_20240518_114323

  • /**
     * 头插法插入结点(新插入的结点总是在老结点的前面,也就是新插入的结点总是在头的后一位)
     * @param L 链表
     * @param n 要插入的结点个数
     */
    void CreateLink_Head(LinkList &L,int n){
        //先建立一个带头结点的空链表
        L = new LNode;
        L->next = nullptr;
        for (int i = 0;i<n;i++){
            //生成一个新的结点
            auto p = new LNode;
            //输入元素值,并赋值给新结点 p 的数据域
            cin >> p->data;
            //将新结点 p 插入到头结点的后面
            p->next = L->next;
            L->next = p;
        }
    }
    
1.2.4、尾插法
  • IMG_20240518_115113

  • /**
     * 尾插法插入结点(新插入的结点总是在老结点的后面)
     * @param L
     * @param n
     */
    void CreateLink_Last(LinkList &L,int n){
        //先建立一个带头结点的空链表
        L = new LNode;
        L->next = nullptr;
        //建立一个尾指针指向最后一个结点,现在没有首结点,指向头结点
        LinkList r = L;
        for (int i = 0;i<n;i++){
            //生成一个新的结点
            auto p = new LNode;
            //赋值
            cin >> p->data;
            //将新结点的next置空
            p->next = nullptr;
            //将最后一个结点的指向,指向新结点
            r->next = p;
            //将尾指针指向最后一个结点
            r = p;
        }
    }
    
1.2.5、完整的代码
  • #include <cstdio>
    #include <iostream>
    using namespace std;
    
    typedef int Status;
    //好处是可以随时修改单链表中的类型
    typedef int ElemType;
    #define OK 0;
    #define ERROR 1;
    
    typedef struct LNode{
        //数据域
        ElemType data;
        //结点的指针域
        struct LNode *next;
    }LNode,*LinkList;   //LinkList为指向结构体LNode的指针类型
    
    
    /**
     * 链表的初始化
     * @param L 链表
     * @return
     */
    Status InitList(LinkList &L){
        //生成一个节点作为头节点,用头指针L指向头结点
        L = new LNode;
        //给指针域置空
        L->next = nullptr;
        return OK;
    }
    
    /**
     * 取值操作---根据序号获取值,并返回
     * @param L 链表
     * @param i 取值的位置
     * @param e 取的值
     * @return
     */
    Status GetElem(LinkList L,int i,ElemType e){
        //初始化,将p指向首元结点
        LinkList p = L->next;
        int j = 1;
        //当p不存在 或者 j的值大于取值序号i时,退出循环
        while (p && j < i){
            //p指向下一个结点
            p = p->next;
            //计数器加一
            ++j;
        }
        //如果p不存在或者j>i时退出
        if(!p || j > i){
            return ERROR;
        }
        e = p->data;
        return OK;
    }
    
    
    /**
     * 通过指定的 值 进行查找,返回结点地址
     * @param L 链表
     * @param e 想要查找的值
     * @return 返回查找到的结点
     */
    LNode *LocateElem(LinkList L,ElemType e){
        //初始化,将p指向首元结点
        LinkList p = L->next;
        //当p不存在 或者 找到结点值等于 e 时循环退出
        while(p && p->data !=e){
            p = p->next;
        }
        return p;
    }
    
    
    /**
     * 插入值
     * @param L 要插入的链表,传入的是地址
     * @param i 插入的位置
     * @param e 插入的值
     * @return
     */
    Status ListInsert(LinkList &L,int i,ElemType e){
        if (i < 1){
            return ERROR;
        }
        //初始化p指向首结点
        LinkList p = L;
        int j = 0;
        //当结点p为null 或者 j = i-1,也就是找到插入位置的前一个结点
        while (p && j < i-1){
            p = p->next;
            ++j;
        }
        //如果p不存在或者j>i-1退出
        if (!p || j > i-1){
            return ERROR;
        }
        //生成一个新结点
        auto s = new LNode;
        //将插入的值赋值给新结点
        s->data = e;
        //将新阶段的指针指向插入位置的后面这个结点
        s->next = p->next;
        //将插入位置前一个结点指向新结点,完成新结点的插入
        p->next = s;
        return OK;
    }
    
    
    /**
     * 删除结点
     * @param L 传入的是链表的地址
     * @param i 指定删除的位置
     * @return
     */
    Status ListDelete(LinkList &L,int i){
        if (i < 1){
            return ERROR;
        }
        //初始化p指向首结点
        LinkList p = L;
        int j = 0;
        //当结点p的next为null,说明已经到了最后一个结点,说明i不合法 或者 j = i-1,也就是找到删除位置的前一个结点
        while (p->next && j < i-1){
            p = p->next;
            ++j;
        }
        //如果p的下一个结点为null说明遍历到了最后一个结点,表示位置i是不合法的,或者j>i-1退出
        if (!p->next || j > i-1){
            return ERROR;
        }
      //保存删除的结点,以备后续释放内存
      LinkList q = p->next;
      //将删除结点的上一个结点的指针,指向删除结点的下一个节点,也就是跨过删除结点
      p->next = q->next;
      delete q;
      return OK;
    }
    
    
    /**
     * 头插法插入结点(新插入的结点总是在老结点的前面,也就是新插入的结点总是在头的后一位)
     * @param L 链表
     * @param n 要插入的结点个数
     */
    void CreateLink_Head(LinkList &L,int n){
        //先建立一个带头结点的空链表
        L = new LNode;
        L->next = nullptr;
        for (int i = 0;i<n;i++){
            //生成一个新的结点
            auto p = new LNode;
            //输入元素值,并赋值给新结点 p 的数据域
            cin >> p->data;
            //将新结点 p 插入到头结点的后面
            p->next = L->next;
            L->next = p;
        }
    }
    
    
    /**
     * 尾插法插入结点(新插入的结点总是在老结点的后面)
     * @param L
     * @param n
     */
    void CreateLink_Last(LinkList &L,int n){
        //先建立一个带头结点的空链表
        L = new LNode;
        L->next = nullptr;
        //建立一个尾指针指向最后一个结点,现在没有首结点,指向头结点
        LinkList r = L;
        for (int i = 0;i<n;i++){
            //生成一个新的结点
            auto p = new LNode;
            //赋值
            cin >> p->data;
            //将新结点的next置空
            p->next = nullptr;
            //将最后一个结点的指向,指向新结点
            r->next = p;
            //将尾指针指向最后一个结点
            r = p;
        }
    }
    
    int main(){
        LinkList L;
        InitList(L);
        CreateLink_Last(L,2);
        ElemType num3 = 3;
        ListInsert(L,3,num3);
        LinkList p = L;
        ListDelete(L,3);
        ListDelete(L,5);
        while (p){
            p = p->next;
            printf("%d ",p->data);
        }
        return 0;
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值