DS博客作业02--线性表

好久不见. 提交于 2020-03-08 19:05:04

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对比,
  还要再舍弃。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!