• 数据结构与算法基础(王卓)(3)


    目录

    前置:

    二、线性表的销毁

    三、线性表的清空

    四、线性表是否为空 

    五、返回线性表元素个数

    六、返回线性表第i个元素值

    重难点算法:(算法时间复杂度:O(n))

    七、查找元素

    八、线性表的插入

    九、线性表的删除

    十、定位元素位序(第几个元素)

    十一、指定元素的前驱与后继

    十二(附加)、对线性表内部所有元素进行统一同一操作


    前置:

    1. //#include
    2. #include//存放exit
    3. #define TRUE 1
    4. #define FALSE 0
    5. #define OK 1
    6. #define ERROR 0
    7. #define INFEASIBLE -1
    8. #define OVERFLOW -2
    9. #define MAXlength 100 //初始大小为100,可按需修改
    10. typedef int Status; //函数调用状态
    11. struct Poly
    12. {
    13. float p;
    14. int e;
    15. };
    16. struct Sqlist
    17. {
    18. Poly* elem;
    19. int length;
    20. };

    位置:PPT第二章:72

    二、线性表的销毁

    1. void DestroyList(Sqlist& L)
    2. {
    3. if (L.elem) delete L.elem;
    4. }

    三、线性表的清空

    1. void ClearList(Sqlist& L)
    2. {
    3. L.length = 0;
    4. //将线性表的长度设置为0
    5. }

    四、线性表是否为空 

    1. int IsEmpty(Sqlist L)
    2. {
    3. if (L.length == 0)
    4. return true;
    5. else
    6. return false;
    7. }

    五、返回线性表元素个数

    1. int Listlength(Sqlist L)
    2. {
    3. return L.length;
    4. }

    、返回线性表第i个元素值

    int GetElem(Sqlist L,int i,Poly ele)//element:元素
    {
        if (i <= 0 || i > L.length)
            return ERROR;
            ele = L.elem[i-1];
            return OK;
    }

    1. int GetElem(Sqlist L,int i,Poly ele)//element:元素
    2. {
    3. if (i <= 0 || i > L.length)
    4. return ERROR;
    5. ele = L.elem[i-1];
    6. return OK;
    7. }

    或者:

    1. bool GetELem(const SqList &L, const size_t i, ElemType &e)
    2. {
    3. if(i<1 || i>MAXSIZE)
    4. {
    5. cerr<<"out of range"<
    6. return false;
    7. }
    8. e = L.elem[i-1];
    9. return true;
    10. }

     ele = L.elem[i-1]:

    elem是结构体Sqlist里面的一个指针(型)变量成员,指向一个Ploy类型的目标变量

    也就是说,其本身就是这个类型的对象的首地址,至于剩下的,就不用我多说了吧

    如果还要我说,那就详见:C语言日记 25 指针与数组_宇 -Yu的博客-CSDN博客


    另外,视频里没有说,但是介绍基本操作时要求的操作:

    定位元素位序(第几个元素)

    指定元素的前驱与后继

    对线性表内部所有元素进行统一同一操作

    这几个操作算法,我们在本文末尾再补充完整

    这个(以上)算法的复杂度都为常量阶O(1)

    顺序表可以随机存取(只要进行一次赋值操作,想要哪个都可以)这是其非常大的优点

    比如链表就没有(不能实现)这样的功能


    重难点算法:(算法时间复杂度:O(n)

    七、查找元素

    project1:

    1. int LocateElem(Sqlist L, Poly i)
    2. {
    3. int a;
    4. for (a = 0; L.elem[a] != i; a++);
    5. cout << "元素序号: " << a << endl;
    6. // cout<<
    7. }

    注意,我们要的,是把所有符合条件的元素筛选出来,而不是只选取第一个:


    project2:

    1. int LocateElem(Sqlist L, Poly i)
    2. {
    3. for (int a = 0; a <= L.length; a++)
    4. {
    5. if (i == L.elem[a])
    6. return a + 1;
    7. return 0;
    8. }
    9. }

    可结果却显示:

     为什么??? 

    完整代码:

    1. #include
    2. #include//OVERFLOW,exit
    3. #define OK 1
    4. struct Poly
    5. {
    6. float p;
    7. int e;
    8. };
    9. struct Sqlist
    10. {
    11. Poly* elem;
    12. int length;
    13. };
    14. int LocateElem(Sqlist L, Poly i)
    15. {
    16. for (int a = 0; a <= L.length; a++)
    17. {
    18. if (i == L.elem[a])
    19. return a + 1;
    20. return 0;
    21. }
    22. }

    原因不在我写的操作函数里,而是在前面的类体当中;

    究其根本原因,还是因为:==不能直接比较结构体,需要手撸比较的工具:

        bool operator==(Poly& t) 
        {
            return t.p == p && t.e == e;
        }


    project 3:

    1. #include//OVERFLOW,exit
    2. #define OK 1
    3. struct Poly
    4. {
    5. float p;
    6. int e;
    7. bool operator==(Poly& t)
    8. {
    9. return t.p == p && t.e == e;
    10. }
    11. };
    12. struct Sqlist
    13. {
    14. Poly *elem;
    15. int length;
    16. };
    17. int LocateElem(Sqlist L, Poly i)
    18. {
    19. for (int a = 0; a <= L.length; a++)
    20. {
    21. if (i == L.elem[a])
    22. return a + 1;
    23. return 0;
    24. }
    25. }
    26. int main()
    27. {
    28. }

     用while语句实现:

    1. #include
    2. #include//OVERFLOW,exit
    3. #define OK 1
    4. struct Poly
    5. {
    6. float p;
    7. int e;
    8. bool operator==(Poly& t)
    9. { return t.p == p || t.e == e; }
    10. bool operator!=(Poly& t)
    11. {
    12. return t.p != p && t.e != e;
    13. }
    14. };
    15. struct Sqlist
    16. {
    17. Poly* elem;
    18. int length;
    19. };
    20. int LocateElem(Sqlist L, Poly i)
    21. {
    22. int a = 0;
    23. while (a <= L.length && i != L.elem[a])
    24. a++;
    25. if(a <= L.length)
    26. return a + 1;
    27. return 0;
    28. }
    29. int main()
    30. {
    31. }

    八、线性表的插入

    project 1:

    1. int ListInsert(Sqlist L,int i,Poly e)
    2. {//insert:插入//i:插入位置(位置序号)
    3. if (i<1 || i>L.length + 1)
    4. return ERROR;
    5. //把插入位置后面的元素全部往后移
    6. for (int j = L.length - 1; j >= i - 1; j--)//j为下标
    7. L.elem[j + 1] = L.elem[j];
    8. //放元素
    9. L.elem[i-1] = e;
    10. return 0;
    11. }

    记得(别忘了)写:

        if (L.length == MAXlength)return ERROR;

        L.length++;

    project 2:

    int ListInsert(Sqlist L,int i,Poly e)
    {//insert:插入//i:插入位置(位置序号)
        if (i<1 || i>L.length + 1)
            return ERROR;
        if (L.length == MAXlength)return ERROR;//当前储存空间已满
        //把插入位置后面的元素全部往后移
        for (int j = L.length - 1; j >= i - 1; j--)//j为下标
            L.elem[j + 1] = L.elem[j];
        //放元素
        L.elem[i-1] =  e;
        L.length++;
        return 0;
    }

    1. //#include
    2. #include//存放exit
    3. #define TRUE 1
    4. #define FALSE 0
    5. #define OK 1
    6. #define ERROR 0
    7. #define INFEASIBLE -1
    8. #define OVERFLOW -2
    9. #define MAXlength 100 //初始大小为100,可按需修改
    10. typedef int Status; //函数调用状态
    11. struct Poly
    12. {
    13. float p;
    14. int e;
    15. };
    16. struct Sqlist
    17. {
    18. Poly* elem;
    19. int length;
    20. };
    21. int ListInsert(Sqlist L,int i,Poly e)
    22. {//insert:插入//i:插入位置(位置序号)
    23. if (i<1 || i>L.length + 1)
    24. return ERROR;
    25. if (L.length == MAXlength)return ERROR;
    26. //把插入位置后面的元素全部往后移
    27. for (int j = L.length - 1; j >= i - 1; j--)//j为下标
    28. L.elem[j + 1] = L.elem[j];
    29. //放元素
    30. L.elem[i-1] = e;
    31. L.length++;
    32. return 0;
    33. }
    34. int main()
    35. {
    36. }

    注意:

    i:位序;不是下标

    j:数组下标(用于访问数据)

    L.length:总的元素个数,i的最大值

    九、线性表的删除

    1. int ListDelete(Sqlist L,int i)
    2. {
    3. if (i < 1 || i > L.length )
    4. return ERROR;
    5. for (int j = i - 1; j <= L.length-1; j++)
    6. L.elem[j] = L.elem[j + 1];
    7. L.length--;
    8. }

    按照书上的写法:(不要忘了:    return OK;)

    1. int ListDelete(Sqlist L,int i)
    2. {
    3. if (i < 1 || i > L.length )
    4. return ERROR;
    5. for (int j = i ; j <= L.length; j++)
    6. L.elem[j-1] = L.elem[j];
    7. L.length--;
    8. return OK;
    9. }
    1. bool EraseList(Sqlist &L, const int &i)
    2. {
    3. //异常判断
    4. if(i<0 || i>L.length)
    5. {
    6. cerr << "wrong erase position!" << endl;
    7. return false;
    8. }
    9. if(L.length == 0)
    10. {
    11. cerr << "List has no length" << endl;
    12. return false;
    13. }
    14. //将位于删除位置之后的元素依次向前挪动一位
    15. for (int p = i + 1; p < L.length; ++p)
    16. {
    17. L.elem[p - 1] = L.elem[p];
    18. }
    19. //线性表长度-1
    20. L.length -= 1;
    21. return true;
    22. //算法时间复杂度:O(n)
    23. }

    视频里没有说,但是介绍基本操作时要求的操作:

    十、定位元素位序(第几个元素)

    1. Status LoacteElem(Sqlist L, Poly e)
    2. {
    3. int i = 0;
    4. if (!&L)//初始条件:L存在
    5. return false;
    6. while (L.elem[i] != e)i++;
    7. if (e == L.elem[i])
    8. cout << "元素位序为:" << i + 1 << endl;
    9. return false;
    10. }

     当然,还得在前面手写等于和不等于判断表达式:

    1. struct Poly
    2. {
    3. float p;
    4. int e;
    5. bool operator==(Poly t)
    6. {
    7. return t.p == p && t.e == e;
    8. }
    9. bool operator!=(Poly t)
    10. {
    11. return t.p != p || t.e != e;
    12. }
    13. };

    Issues:

    (1):为什么赋初值时 i = 0;(为什么赋给i = 0?)输出结果时输出 i + 1?

    i = 0:

    显然,线性表以数组形式进行存储,而数组下标下限默认为0;所以在赋初值时必须令 i = 0(而不是 i = 1)

    实现让程序从访问数组首个元素开始对线性表(内的)元素逐个访问寻找元素

    输出 i + 1:

    每个元素的位序恰巧为其下标加一(例:第一个元素的下标为零)

    而在程序跳出其中的while循环以后,i的值恰好为我们所要定位的元素的下标

    所以在输出时,其元素位序即为i + 1;


    (2):更改为下图形式为什么会报错?

    详细地说:

    数组名不是既可以代表(代指)整个数组,又可以代指这个数组的头指针(首个元素的地址)吗?

    那么,为什么

    • (!L)无法代表线性表首元素地址
    • L->elem无法访问线性表内的元素
    • 无法用L = (L + 1)让线性表指向下一位地址

     ???

    原因其实很简单:

    L在程序里,作为一个采用引用传值的变量

    传过来的默认就是一个线性表,自然无法被看作是一个头指针了

    至于为什么不能写L->elem,必须写成 L.elem[i]:

    因为我们定义的 Poly* elem本身就是一个指向(Poly型)目标对象的指针

    如果一定要使用指针访问来实现这个操作算法,那就利用L.elem作为指针:

    1. Status LoacteElem(Sqlist& L, Poly e)
    2. {
    3. int i = 0;
    4. if (!&L)//初始条件:L存在
    5. return false;
    6. while (*(L.elem) != e)
    7. {
    8. L.elem= L.elem + 1;
    9. i++;
    10. }
    11. if (e == *(L.elem))
    12. cout << "元素位序为:" << i + 1 << endl;
    13. return false;
    14. }

    在elem不是指针类型(Poly elem)时:(用指针访问)    

    1. Status LoacteElem(Sqlist& L, Poly e)
    2. {
    3. int i = 0;
    4. auto p = &L.elem;
    5. if (!&L)//初始条件:L存在
    6. return false;
    7. while (*p != e)
    8. {
    9. p++;
    10. i++;
    11. }
    12. if (e == (L.elem))
    13. cout << "元素位序为:" << i + 1 << endl;
    14. return false;
    15. }

    注意:这种情况下(elem不是指针类型),不能再想当然地,简单用 

    &L.elem = &L.elem + 1;

     来实现由当前元素转移到下一元素,结果:

    十一、指定元素的前驱与后继

    前驱:

     

    1. Status PriorElem(Sqlist& L, Poly e_current, Poly& e_prior)
    2. {
    3. int i = 0;
    4. if (!&L || L.elem[i] != e_current)
    5. //L存在且e_current不是第一个元素
    6. cerr << "无意义" << endl;
    7. return false;
    8. while (L.elem[i] != e_current)i++;
    9. e_prior = L.elem[i - 1];
    10. return true;
    11. }

    后继:

    1. Status NextElem(Sqlist& L, Poly e_current, Poly& e_next)
    2. {
    3. int i = L.length - 1;
    4. if (!&L || L.elem[i] != e_current)
    5. //L存在且e_current不是最后一个元素
    6. cerr << "无意义" << endl;
    7. return false;
    8. while (L.elem[i] != e_current)i--;
    9. e_next = L.elem[i + 1];
    10. return true;
    11. }

    十二(附加)、对线性表内部所有元素进行统一同一操作

    :对元素进行操作的内容;

    例如:我们在这里给实数加一

    (1)在函数内部实现:

    1. Status ListTraverse(Sqlist& L)
    2. {
    3. if (!&L)
    4. return false;
    5. int i = 0;
    6. while (i < L.length-1)
    7. {
    8. (L.elem->p)++;
    9. i++;
    10. }
    11. return true;
    12. }

    (2)在操作函数外部通过构造visit函数(辅助)实现

    1、visit函数在结构体内部:

    1. struct Sqlist
    2. {
    3. Poly* elem;
    4. int length;
    5. int visit()
    6. {
    7. int i = 0;
    8. while (i < length - 1)
    9. {
    10. elem->p++;
    11. i++;
    12. }
    13. return true;
    14. }
    15. };
    16. Status ListTraverse(Sqlist& L)
    17. {
    18. if (!&L)
    19. return false;
    20. int visit();
    21. return true;
    22. }

    这样,在修改对线性表的元素的操作时只需修改visit函数即可

    2、visit函数在结构体体之外(独立,自成一派):

    1. struct Sqlist
    2. {
    3. Poly* elem;
    4. int length;
    5. };
    6. int visit(Sqlist& L)
    7. {
    8. int i = 0;
    9. while (i < L.length - 1)
    10. {
    11. L.elem->p++;
    12. i++;
    13. }
    14. return true;
    15. }
    16. Status ListTraverse(Sqlist& L)
    17. {
    18. if (!&L)
    19. return false;
    20. int visit();
    21. return true;
    22. }

    注意:

    这里(面)用的结构体不是类,不可能存在说像类一样把成员函数定义在其结构体范围之外 

    也不存在在这个地方用什么友元函数

    有关于线性表的所有基本操作到此为止,完结撒花

    下一节,我们开关于链表的学习 

  • 相关阅读:
    最近石家庄爆火的社区团购模式系统,你知道吗?
    PHP做app扫码登录的一些步骤和代码片段记录一下
    C++之多态二三事
    在linux中详细解释下kill命令,不同信号的含义及使用场景
    花菁染料CY3/CY5.5/CY7标记壳多糖/壳聚糖/菊粉/果胶,CY3/CY5.5/CY7-Chitin/Chitosan/Inulin/Pectin
    最近 火火火 的开源项目
    Spring Boot框架以及它的优势
    基于BP神经网络对鸢尾花数据集分类
    有哪些开源通用流程引擎
    COLE HERSEE 48408 工业4.0、制造业X和元宇宙
  • 原文地址:https://blog.csdn.net/Zz_zzzzzzz__/article/details/128104788