zoukankan      html  css  js  c++  java
  • DS博客作业02--线性表

    0.PTA得分截图


    1.本周学习总结

    1.1 总结线性表内容

    1.顺序表结构体定义、顺序表插入、删除的代码操作

    
      顺序表的定义:
      线性表的顺序存储又称为顺序表。
      它用一组地址连续的存储单元,依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也相邻。
      第 1 个元素存储在线性表的起始位置,第 i 个元素的存储位置后面紧接着存储的是第 i+1 个元素。
      因此,顺序表的特点是表中元素的逻辑顺序与其物理顺序相同。
      
      
    
    

       
       顺序表结构体的定义:typedef int ElemType即是定义数据元素类型,可以适应更多类型;
       typedef struct的内容就是定义了定义顺序表类型,只是定义了一个类型,而不是变量;
       顺序表结构的定义,对于在代码的后续操作起着关键性作用,所以在结构体的定义中要仔细。
    
    

    
       顺序表插入、删除的代码操作:顺序表的插入和删除操作,在顺序表开始寻找到相对性的数值,
       就开始执行操作。删除操作针对于区间删除来说,先从第一个for循环开始执行,定义三个变量,
       找到重复元素就开始删除操作。顺序表的插入删除都是要遍历链表,找到相对应的元素进行操作。
    
    


    2.链表结构体定义、头插法、尾插法、链表插入、删除操作

    
        链表结构体的定义:对于单链表而言,先定义的一个结构体用来描述单链表的结点。从这个结构
        定义中,我们知道,结点由存放数据元素的数据域存放后继结点地址的指针域组成。对于ElemType
        就是定义一个结构体成员,struct Node* next的语句对于链表的结点指向的操作,其中每个数据
        分为两部分,一部分是数据存储的位置,称为数据域,另外指针所存储的地方,称为指针域。
    
    

    
       头插法建链表操作:从一个空表开始,重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,
       然后将新结点插入到当前链表的表头结点之后,直至读入结束标志为止。首先对于链表L申请空间,再
        L->next=NULL指向空指针,LinkList s,申请新的链表s,用s来保留L的->next,再通过s插入数据
    
    

    
       尾插法建链表:将新结点插到当前链表的表尾上,增加一个尾指针,使之指向当前链表的表尾。
       尾插法建链表比从头插法建链表操作多一个尾结点tail,用tail->next尾部插入数据
    
    


    链表插入:

    链表删除:


    3.有序表,尤其有序单链表数据插入、删除,有序表合并

    
       有序单链表数据插入,删除:所谓有序表,其中所有元素以递增或者递减方式有序排列;有序表
       包含于线性表;有序表和线性表中元素之间的逻辑关系相同,其区别是运算实现的不同。
    
    

    有序单链表插入:

    有序单链表删除:

    有序表合并:

    伪代码:

    新建顺序表LC;
    i表示LA的下标,j表示LB的下标
    while(i<LA.length&&j<LB.length)
    {
      if(LA->data[i]<LB->data[j]) 则LC中插入元素LA->data[i],i++;
      else 插入元素LB->data[j],j++
      LC数组长度加1;
    }
    查看LA或者LB是否扫描完毕,没扫描玩把剩余元素复制插入LC
    
    

    归并(没有显示重复数据)


    4. 循环链表、双链表结构特点

    
        双链表:双链表每个节点有2个指针域。一个指向后续节点,一个指向前驱结点。
        
    
    

    类型定义:

    
    typedef struct DNode { //定义双链表结点类型
        ElemType data; //数据域
        struct DNode *prior,*next; //前驱和后继指针
    } DNode *DLinklist;
    
    

    双链表中的插入结点操作语句:

    
    s->next=p->next;
    p->next->prior=s;
    s->prior=p;
    p->next=s;
    
    

    双链表删除结点操作:

    
    p->next->next->prior=p;
    p->next=p->next->next;
    
    

    
       循环链表:循环链表是另一种形式的链式存储结构形式。将表中尾结点的指针域改为
       指向表头结点,整个链表形成一个环。由此从表中任意节点出发均可以找到链表中其他
       节点。循环双链表与非循环相比,链表中没有空指针域;p所指结点为尾结点的条件:
        p->next==L;一步操作既可以找到尾结点
     
    
    


    5.线性表特点

    
      表中元素的个数有限。
      表中元素具有逻辑上的顺序性,在序列中各元素排序有其先后次序。
      表中元素都是数据元素,每一个元素都是单个元素。
      表中元素的数据类型相同,这意味着每一个元素占有相同大小的存储空间。
      表中元素具有抽象性。即仅讨论元素间的逻辑关系,不考虑元素究竟表示什么内容。
      线性表是一种逻辑结构,表示元素之间一对一的相邻关系。
      顺序表和链表是指存储结构,两者属于不同层面的概念
    
    

    6.线性表基本操作

    
      InitList(&L):初始化表。构造一个空的线性表。
      Length(L):求表长。返回线性表 L 的长度,即 L 中数据元素的个数。
      LocateElem(L,e):按值查找操作。在表 L 中査找具有给定关键字值的元素。
      GetElem(L,i):按位査找操作。获取表 L 中第 i 个位置的元素的值。
      ListInsert(&L,i,e):插入操作。在表 L 中第 i 个位置上插入指定元素 e。
      ListDelete(&L,i,&e):删除操作。删除表 L 中第 i 个位置的元素,并用 e 返回删除元素的值。
      PrintList(L):输出操作。按前后顺序输出线性表 L 的所有元素值。
      isEmpty(L):判空操作。若 L 为空表,则返回true,否则返回false。
      DestroyList(&L):销毁操作。销毁线性表,并释放线性表 L 所占用的内存空间。
      
    

    1.2谈谈你对线性表的认识及学习体会。

    
       线性表因存储结构的不同,分为顺序表和链表。顺序表适合于查找、修改第i个结点的值(其时间复杂度为O(1)),
       但插入或者删除结点就要每次都移动数组,比较麻烦。链表适合用于插入删除某个结点,比较灵活,也比较绕。
       在打pta的过程中,由于大多数都没有注意到一些基础函数,在打编程题的时候就一直各种错误,尤其是初始化链表,
       一直出现段错误,在链表中还要注意不能出现野指针,所以要提高正确率,最好要学会背代码....
    
    

    2.PTA实验作业

    2.1.题目1:有序链表合并

    2.1.1代码截图


    2.1.2本题PTA提交列表说明。

    
      Q1:最开始的时候出现段错误。
      A1:没有对L3进行初始化
      Q2:中间部分出现部分正确
      A2:因为在复制上一段代码的时候,在重复数据出现时候忘记p=p->next
    
    

    2.2.题目2:链表倒数第m个数

    2.2.1代码截图

    2.2.2本题PTA提交列表说明

    
      Q1:编译错误从VS转移代码的时候最后漏掉}
      A1:加上}
      Q2:一开始的运行超时是while里面忘记让用来遍历的pre指针往后移了,导致while出不来,就运行超时了。
      A2:添加了一个pre=pre->next
      Q3:编译错误就是承接上一个错误,添加了pre=pre->next,变量时ptr
      A3:pre=pre->next改成ptr=ptr->next
    
    

    2.3.题目3:一元多项式的乘法与加法运算

    2.3.1代码截图



    2.3.2本题PTA提交列表说明

    
      Q1:编译错误
      A1:加逗号
      Q2:段错误,在for循环发生错误,for (int i = N - 1;i >= 0;i++)编写错误
      A2:改为for (int i = N - 1;i >= 0;i--)
      Q3:部分正确,就是答案的格式错误
      A3:结尾改为cout << "0 0"
    
    

    3.阅读代码

    3.1 题目及解题代码

    题目:

    解题代码:

    
    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    # define MAXSIZE 1000
    typedef int ElemType;
    typedef struct {
        ElemType data[MAXSIZE];
        int length;
    }Vector;
    Vector* CircleLeftMove(Vector* v, int p) {
        Vector* v_temp = (Vector*)malloc(sizeof(Vector));
        v_temp->length = p;
        int i;
        for (i = 0; i < v->length; i++) {
            v_temp->data[i] = v->data[i];
            v->data[i] = v->data[i + p];
        }
        for (i = 0; i < p; i++) {
            v->data[v->length - p + i] = v_temp->data[i];
        }
        return v;
    }
    
    

    3.1.1 该题的设计思路

    
       借助辅助数组v_temp存储原表的前p个元素,并把原顺序表中p之后的元素顺序前移,
       然后将v_temp中暂存的p个数的元素依次放回到原顺序表的后续单元。
       时间复杂度为O(n)
       空间复杂度为O (p)
    
    

    3.1.2 该题的伪代码

    
      定义data的数组空间大小,链表长度
      申请v_temp空间
      v_temp->length = p存储前p个元素
      for(原顺序表中p之后的元素顺序前移)
      v_temp中暂存的p个数的元素依次放回到原顺序表的后续单元;
      return v;
    
    

    3.1.3 运行结果

    3.1.4分析该题目解题优势及难点。

    
      1.使用静态分配的方式创建一维数组:数组的大小和空间固定,一旦占满再加入新的数据会导致程序崩溃
      2.运用辅助数组v_temp来存储元素,再进行前移再放回,思路很清晰
    
    

    3.2题目及解题代码

    题目:

    解题代码:

    
    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    # define MAXSIZE 1000
    typedef int ElemType;
    typedef struct {
        ElemType data[MAXSIZE];
        int length;
    }Vector;
    int getMidByCompare(Vector v1, Vector v2) {
        int num1 = 0, num2 = 0; 
        int end1 = v1.length - 1;
        int end2 = v2.length - 1;
        int mid1, mid2;
        while (num1 != end1 || num2 != end2) {
            mid1 = (num1 + end1) / 2;
            mid2 = (num2 + end2) / 2;
            if (v1.data[mid1] == v2.data[mid2]) {
                return v1.data[mid1];
            }
            if (v1.data[mid1] < v2.data[mid2]) {
                if ((num1 + end1) % 2 == 0) {
                    
                    num1 = mid1; 
                    end2 = mid2;
                }
                else {
                    num1 = mid1 + 1; 
                    end2 = mid2;
                }
            }
            else {
                if ((num2 + end2) % 2 == 0) {
                    end1 = mid1;
                    num2 = mid2;
                }
                else {
                    end1 = mid1;
                    num2 = mid2 + 1; 
                }
            }
        }
        return v1.data[num1] < v2.data[num2] ? v1.data[num1] : v2.data[num2];
    }
    
    

    3.2.1该题的设计思路

    
         1.若v1.data[mid1] == v2.data[mid2],则mid1和mid2即为所求中位数,立即返回。
         2.若v1.data[mid1] < v2.data[mid2]2,则序列1中比mid1还要小数必不可能为所求中位数,故舍弃序列1中较小的一半;同理,这时也要舍弃序列2中较大的一半。
         3.若v1.data[mid1] > v2.data[mid2], 则舍弃序列1中大于mid1的数,同时也要舍弃序列2中较小的一半,直到逻辑上的序列只含一个元素时,较小者即为所求中位数。
         4.时间复杂度:O(log2n)。
         5.空间复杂度:O(1)。
    
    

    3.2.2该题的伪代码

       定义data的数组空间大小,链表长度
       int num1,num2;
       num结点始终指向序列中的第一个元素的下标
       定义end结点始终指向序列中的最后一个元素的下标 
       int mid1,mid2;
       while(还没找到最后一个元素循环)
      {
         找到中位数下标;
         if(相等) return ;
         if(v1.data[mid1] < v2.data[mid2])
         {
            if(v1的元素个数为奇数)  舍弃序列1中位数前的元素;
            else 弃序列1中位数及中位数前的元素;
         }
         else 序列1的中位数大于序列2的中位数
         { 
            if(v2的元素个数为奇数) 舍弃序列1中比中位数大的元素;
            else  舍弃序列2的中位数及比中位数小的元素 ;
         }
    
      }
       return v1.data[num1] < v2.data[num2] ? v1.data[num1] : v2.data[num2];
    
    

    3.2.3运行结果

    3.2.4分析该题目解题优势及难点。

      该题要找出中位数,先用了num来指向序列中的第一个元素的下标 ,和end指向序列中的最后
      一个元素的下标 ;感觉看起来还是有点麻烦,不是很能懂;难点在于找到序列1和2对比,
      还要再舍弃。
    
    
  • 相关阅读:
    php 小知识随手记 new self() 和new static()作用和区别
    静态页面制作:16结构与表现分离
    静态页面制作:15标签样式初始化
    静态页面制作:14综合实践
    静态页面制作:13padding的用法
    静态页面制作:12盒模margin特殊情况
    静态页面制作:11盒子模型
    通过JavaScript实现打印页面
    静态页面制作:10样式实战
    Handsontable-一款仿 Excel 的效果的表格插件使用总结
  • 原文地址:https://www.cnblogs.com/w-y-h--/p/12424661.html
Copyright © 2011-2022 走看看