【408数据结构】线性表-顺序表

目录

顺序表

顺序表--静态分配

顺序表--动态分配

顺序表--应用

T1.把n个整数存放在一维数组R----ab转换为ba​编辑设计思想:把数组ab转换为ba,a为数组中前p个数,b为后n-p个数。设置一个函数reverse将a进行元素逆置,则先后对a、b逆置得到&a,&b(ab的逆置就是&b&a),再将&a&b逆置得到ba。

T2找出两个等长升序序列A和B的中位数

T3含n个整数的数组,找出未出现的最小正整数。

T4非空整数集合存储在3个数组中,计算三元组最小距离。


数据结构三要素——逻辑结构、物理结构、数据的运算。

逻辑结构------线性表。

物理结构(线性表的实现)------顺序---顺序表、链式---单-双-循环-静态......

线性表:相同数据类型、有限序列。

顺序表(线性表的顺序存储结构):元素的逻辑顺序与物理顺序相同;随机存取(随机访问);存取密度高(每个结点只存储数据元素);拓展容度不方便。

单链表、双链表、循环链表(指针实现)。

静态链表(借助数组实现)。

顺序表

顺序表--静态分配

线性表的顺序存储类型(静态分配数组空间):

#define Maxsize 50
typedef struct{
    ElemType data[Maxsize];//元素
    int length;//顺序表当前长度
}SqList;//顺序表的类型定义

顺序表--动态分配

线性表的顺序存储类型(动态分配数组空间):

#define InitSize 100    //表长度的初始定义
typedef struct{
    ElemType *data;    //动态分配数组的指针
    int MaxSize,length;    //最大容量,当前个数
}SeqList;    //动态分配数组顺序表的类型定义
//C的初始动态分配语句,将malloc返回的指针强制转型为elemtype类型
L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);

//C++初始动态分配语句
L.data=new Elemtype[InitSize];

动态分配并不是链式存储,它同样属于顺序存储结构(物理结构没有变化),依然是随机存取方式,只是分配的空间大小在运行时动态决定。

顺序表--应用

在顺序表L的第i个位置插入新元素-----说明表里第i个是新元素------所以1<=i<=L.length+1平均时间复杂度为O(n)。

在顺序表L的第i个位置删除元素-----说明表里第i个是被删除元素,用引用变量e返回------所以1<=i<=L.length。平均时间复杂度为O(n)。

T1.把n个整数存放在一维数组R----ab转换为ba设计思想:把数组ab转换为ba,a为数组中前p个数,b为后n-p个数。设置一个函数reverse将a进行元素逆置,则先后对a、b逆置得到&a,&b(ab的逆置就是&b&a),再将&a&b逆置得到ba。

void reverse(int R[], int from, int to) {
    int i, temp; // 定义变量i作为循环索引,temp作为临时交换变量
  
    // 使用for循环来遍历数组R中从索引from到to的部分,并进行逆置
    // 注意:to、from是数组下标=元素位序下标-1,从0开始记。
    for(i = from; i <= (to - from) / 2; i++) { 
        // 进行元素交换
        temp = R[i]; // 先保存R[i]的值到temp
        R[i] = R[to - i]; // 将R[to-i]的值赋给R[i]    
        R[to - i] = temp; // 最后将temp(即原R[i]的值)赋给R[to-i]
    }
}
//为了避免可能的误解并确保逻辑清晰,建议将循环条件改为`i < (to - from + 1) / 2`。这样,在处理元素个数为奇数的情况时,逻辑会更加直观且不易出错。

void converse(int R[],int p,int n){
  reverse(R,0,p-1);//时间复杂度为O(p/2)
  reverse(R,p,n-1);//时间复杂度为O((n-p)/2)
  reverse(R,0,n-1);//时间复杂度为O(n/2)
}

以上算法的时间复杂度为O(n),空间复杂度为O(1)。

T2找出两个等长升序序列A和B的中位数

1.设计思想:逐个比较,直到第L/2个数。(不确定对错)

int compare(int A[],int B[],int n){
  //n是A,B序列的长度
  int i,j,e;
  for(i=1,j=1;i+j-2<n;){
    if (A[i-1]<=B[j-1]){
      e=A[i-1];
      i++;
    }
    else{
      e=B[j-1];
      j++;
    }
  }
  return e;
}

法2.参考答案设计思想:

int search(int A[],int B[],int n){
  int s1=0,d1=n-1,m1,s2=0,d2=n-1,m2;
  //分别表示序列A和B的首位数s=0、末位数d=n-1和中位数m=n/2-0.5
  while(s1!=d1||s2!=d2){
    m1=(s1+d1)/2;  //相当于向下取整了欸。
    m2=(s2+d2)/2;
    if(A[m1]==B[m2]){
      return A[m1];
    }
    if(A[m1]<B[m2]){
      if((s1+d1)%2==0){   //若元素个数为奇数。
        s1=m1;   //舍弃A中间点以前的部分,且保留中间点
        d2=m2;   //舍弃B中间点以后的部分,且保留中间点
      }
      else{
        s1=m1+1;  //舍弃A中间点以及以前的部分
        d2=m2;    //舍弃B中间点以后的部分,且保留中间点
      }
    }
    else{
      if((s2+d2)%2==0){
        d1=m1;
        s2=m2;
      }
      else{
        d1=m1;
        s2=m2+1;
      }
    }
  }
  return A[s1]<B[s2]?A[s1]:B[s2];
}

算法的时间复杂度为O(log_2n),空间复杂度为O(1)。

T3含n个整数的数组,找出未出现的最小正整数。

设计思路:要求在时间上尽可能高效,因此采用空间换时间的办法,分配一个用于标记的数组B用来记录A中是否出现了1~n中的正整数。那么B[0]就对应正整数1,B[n-1]就对应正整数N,初始化B中全部为零。

由于A中含有N个整数,因此最小正整数可能返回的值是1~n+1。当A中n个数恰好为1~n时,返回n+1。

当数组A中出现了>=0或>N的值时,会导致1~n中出现空余位置返回,结果必然在1~n中。因此,对于A中出现了>=0或>N的值,可以不采取任何操作。

经过以上分析,可以得出算法流程从A[0]开始遍历A。如果0<A[i]<=n,则令B[A[i]-1]=1,否则不做操作。

对A遍历结束之后,开始遍历数组B。如果能查到第一个满足B[i]==0的下标返回i+1即为结果,说明此时A中未出现的最小正整数在1~n之间。如果B[i]全部不为零,返回i+1,即n+1(跳出循环时,i=n,i+1=n+1)。此时说明A中未出现的最小正整数为n+1。

int findmin(int A[],int n){
  int i;
  int *B;
  B=(int*)malloc(sizeof(int)*n);   //分配空间!!!
  memset(B,0,sizeof(int)*n);    //赋初始值为0!!!
  for(i=0;i<n;i++){
    if(A[i]>0&&A[i]<=n){    //不能直接写0<A[i]<=n!!!
      B[A[i]-1]=1;
    }
  }
  //或者用while
  //i=0;
  //while(B[i]!=0&&i<n){i++;}
  for(i=0;i<n;i++){
    if(B[i]==0) break;
  }
  return i+1;
}

注意分配空间malloc!!!还有赋初始值memset!!!条件用&&

遍历A一次,遍历B一次,两次循环内操作都是O(1)量级,相加就是O(2n)=O(n),时间复杂度为O(n);额外分配了B[n],空间复杂度为O(n)。

T4非空整数集合存储在3个数组中,计算三元组最小距离。

设计思想:

以上是对于三个数的计算方法,即计算最大值和最小值之差的两倍。

思路就是:计算初始最小距离,遍历更新最小距离。

#define INT_MAX 0x7fffffff
//这一行是一个预处理器指令,用于定义一个常量INT_MAX,其值为0x7fffffff。
int abs_(int a){
  if(a<0) return -a;
  else return a;
}
bool a_min(int a,int b,int c){
  if(a<=b&&a<=c) return ture;
  return false;
}
int findmin(intA[],int n1,intB[],int n2,int C[],int n3){
  //D_Min用于记录三元组的最小距离,初始值赋为INT_MAX。
  int i=0,j=0,k=0,D_Min=INT_MAX,D;
  while(i<n1&&j<n2&&k<n3&&D_Min>0){   //这里为什么还需要特别加上D_Min>0?
    D=abs_(A[i]-B[j])+abs_(B[j]-C[k])+abs_(C[k]-A[i]);//计算D
    if(D<D_Min) D_Min=D;//更新D
    if(a_min(A[i],B[j],C[k])) i++;//更新a
    else if(a_min(B[j],A[i],C[k])) j++;
    else k++;
  }
  return D_Min;
}

INT_MAX表示什么意思?在32位系统中,这个十六进制数0x7fffffff代表了整型变量所能表示的最大正整数值,即2147483647。通常用来作为算法中一个非常大的初始值或者边界值

为什么是这样个更新法?(保持较大的两个值不变,将最小的数更新?)结合分析,注意到D的值可以由固定c,更新a(最小值)来计算,而且注意这是一个升序数组,更新a,即把最小值变大了,D会变小!

设n=(|S_1|+|S_2|+|S_3|),则时间复杂度为O(n),空间复杂度为O(1)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值