2021年3月18日-3月21日学习笔记

2021年3月18日-3月21日学习笔记

数据结构与算法线性表

1.从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。空出的位置由最后一个元素填补,若顺序表为空,则显示出错误信息并退出运行。

bool Del_Min(sqList &L,Elemtype &value){
  //删除顺序表L中最小值元素结点,并通过引用型参数value返回值
  //若删除成功,则返回true,否则返回false
  if(L.length==0)
    return false;
  value=L.data[0];
  int pos=0;
  for(i=0;i<L.length;i++)
    if(L.data[i]<value){
      value=L.data[i];
      pos=i
    }
  L.data[pos]=L.data[L.length-1];
  L.length--;
  return true;
}

2.设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)。

void Reverse(Sqlist &L){
  Elemtype temp;    //辅助变量
  for(i=0;i<L.length/2;i++){
    temp=L.data[i];   //交换L.data[i]与L.data[L.length-i-1]
    L.data[i]=L.data[L.length-i-1];
    L.data[L.length-i-1]=temp;
  }
}

3.对长度为n的顺序表L,编写一个时间复杂度为O(n)、空间复杂度为O(1)的算法,该算法删除线性表中所有值为x的数据元素。

//解法一
void del_x_1(Sqlist &L,ElemType x){
  //本算法实现删除顺序表L中所有值为x的数据元素
  int k=0//记录不等于x的元素个数
  for(i=0;i<L.length;i++)
    if(L.data[i]!=x){
      L.dta[k]=L.data[i]
      k++;
    }
  L.length=k;
}

//解法二
void del_x_2(Sqlist &L,ElemType x){
  int k=0,i=0;    //k记录等于x的元素个数
  while(i<L.length){
    if(L.data[i]==x)
      k++;
    else
      L.data[i-k]=L.data[i]; //当前元素前移k个位置
    i++}
  L.length=L.length-k;   //顺序表L的长度递减
}

4.从有序顺序表中删除其值在定值s与t之间(要求s<t)的所有元素,若s或t不合理或顺序表为空,则显示出错信息并退出运行。

bool Del_s_t2(SqList &L,ElemType s,ElemType t){
  //删除有序顺序表L中值在给定值s与t之间的所有元素
  int i,j;
  if(s>=t||L.length==0)
    return false;
  for(i=0;i<L.length&&L.data[i]<s;i++);
  if(i>L.length)
    return false;
  for(j=i;j<L.length&&L.data[j]<=t;j++);
  for(;j<L.length;i++,j++)
    L.data[i]=L.data[j];
  L.length=i;
  return true;
}

bool Del_s_t2(Sqlist &L,ElemType s,ElemType t){
   //删除有序顺序表L中值在给定值s与t之间的所有元素
  int i,j;
  if(s>=t||L.length==0)
    return false;
  for(i=0;i<L.length$$L.data[i]<s;i++);
  if(i>L.length)
     return false;
  for(j=i;j<=L.length&&L.data[j]<=t;j++);
  for(;j<L.length;i++,j++)
    L.data[i]=L.data[j];
  L.length=i;
  return true
}

5.从顺序表中删除其值在给定值s与t之间(包含s和t,要求s<t)的所有元素,若s或t不合理或顺序表为空,则显示出错信息并退出运行。

bool Del_s_t(Sqlist &L,ElemType s,ElemType t){
   //删除有序顺序表L中值在给定值s与t之间的所有元素
  int i,k=0;
  if(L.length==0||s>=t)
    return false;
  for(i=0;i<L.length;i++){
    if(L.data[i]>=s&&L.data[i]<=t)
      k++;
    else
      L.data[i-k]=L.data[i];
  }
  L.length-=k
  return true
}

6.从有序顺序表中删除所有其值重复的元素,使表中的元素均不同。

bool Delete_Same(SeqList &L){
  if(L.length==0)
    return false;
  int i,j;
  for(i=0,j=1;j<L.length;j++)
    if(L.data[i]!=L.data[j])
      L.data[++i]=L.data[j];
  L.length=i+1;
  return true;
}

7.将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。

bool Merge(SeqList A,SeqList B, SeqList &C){
  //将有序顺序表A与B合并为一个新的有序顺序表C
  if(A.length+B.length>C.maxSize)
    return false;
  int i=0,j=0,k=0;
  while(i<A.length&&j<B.length){
    if(A.data[i]<=B.data[j])
      C.data[k++]=A.data[i++];
    else
      C.data[k++]=B.data[i++];
  }
  while(i<A.length)
    C.data[k++]=A.data[i++];
  while(j<B.length)
    C.data[k++]=B.data[j++];
  C.length=k;
  return true;
}

8.已知在一维数组A[m+n]中依次存放两个线性表(a1,a2,a3,…,am)和(b1,b2,b3,…,bn)。试编写一个函数,将数组中的两个顺序表的位置互换,即将(b1,b2,b3,…,bn)放在(a1,a2,a3,…,am)的前面。

Typedef int DataType;
void Reverse(DataType A[],int left,int right,int arraySize){
  if(left>=right||right>=arraySize)
     return;
  int mid=(left+right)/2;
  for(i=0;i<mid-left;i++){
    Datatype temp=A[left+i];
    A[left+i]=A[right-i];
    A[right-i]=temp;
  }
}

void Exchange(DataType A[],int m,int n,int arraySize){
  Reverse(A,0,m+n-1,arraySize);
  Reverse(A,0,n-1,arraySize);
  Reverse(A,n,m+n-1,arraySize);
}

9.线性表(a1,a2,a3,…,an)中的元素递增有序且按照顺序存储于计算机内。要求设计一个算法,完成用最少的时间在表中查找数值为x的元素,若找到,即将其与后继元素位置想交换,若找不到,则将其插入表中并使表中元素仍递增有序。

void SearchExchangeInsert(ElemType A[],ElemType x){
  int low=0,high=n-1,mid;
  if(low<=high){
    mid=(low+high)/2
    if(A[mid]==x) break;
    else if(A[mid]<x) low=mid+1;
    else high=mid-1
  }
  if(A[mid]==x&&mid!=n-1){
    t=A[mid];A[mid]=A[mid+1];A[mid+1]=t
  }
  if(low>high){
    for(i=n-1;i>high;i--) A[i+1]=A[i];
    A[i+1]=x;
  }
}

10.设将n(n>1)个整数存放到一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据由(X0,X1,X2,…,Xn-1)变换为(Xp,Xp+1,…,Xn-1,X0,X1,X2,…,Xp-1)。要求:

1)给出算法的基本设计思想

可将这个问题视为把数组ab转换成数组ba(a代表前p个元素,b代表后n-p个元素),先将a逆置,再将b逆置,最后对整个拟置,过程如下:
Reverse(0,p-1)
Reverse(p,n-1)
Reverse(0,n-1)

2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释

void Reverse(int R[],int from,int to){
  int i,temp;
  for(i=0;i<(to-from+1)/2;i++){
    temp=R[from+i];
    R[from+i]=R[to-i];
    R[to-i]=temp;
  }
}
void Converse(int R[],int n,int p){
  Reverse(R,0,p-1);
  Reverse(R,p,n-1);
  Reverse(R,0,n-1);
}

3)说明你所设计的算法时间复杂度和空间复杂度

上述算法的三个Reverse函数的时间复杂度分别为 O(p/2) O(n-p/2) O(n/2) 故所设计的算法的时间复杂度为 O(n) 空间复杂度为O(1

11.一个长度为L(L>=1)的升序序列S,处在第[L/2]个位置的数称为S的中位数。例如,若序列S1=(11,13,15,17,19),则S1的中位数是15,两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若S2=(2,4,6,8,20),则S1和S2的中位数为11.现在有两个等长升序序列A和B,试设计一个在时间和空间两方面尽可能高效的算法,找出两个序列A和B的中位数。要求:

1)给出算法的基本设计思想

分别求升序序列A和B的中位数,设为a和b,求序列A、B的中位数的过程如下:
1)若a=b,则a或b即为所求中位数,算法结束
2)若a<b,则舍弃序列A中较小的一半,同时舍弃序列b中较大的一半,要求两次舍弃的长度相等。
3)若a>b,则舍弃序列A中较大的一半,同时舍弃序列B中较小的一半,要求两次舍弃的长度相等。
在保留的两个升序序列中,重复过程1),2),3),直到两个序列中均只含有一个元素时为止,较小值即为所求的中位数。

2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释

int M_Search(int A[],int B[]int n){
  int s1=0,d1=n-1,m1,s2=0,d2=n-1,m2;
  //分别表示序列A和B的首位数、末位数和中位数
  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+m1)%2==0){   //元素个数为奇数
        s1=m1;
        d2=m2;
      }
      else{               //元素个数为偶数
        s1=m1+1;
        d2=m2;
      }
    }
    else{
      if((s1+m1)%2==0){   //元素个数为奇数
        d1=m1;
        s2=m2;
      }
       else{             //元素个数为偶数
        d1=m1;
        s2=m2+1;
      }
    }
  }
  return A[s1]<A[s2]?A[s1]:A[s2];
}

3)说明你所设计的算法时间复杂度和空间复杂度

算法的时间复杂度为O(log2n) 空间复杂度为O(1

1)给出算法的基本设计思想

1.选取候取的主元素。依次扫描数组中的每个整数,降低一个遇到的整数保存到c中,记录出现的次数NUM为1.若遇到下一个整数仍为NUM,则计数加一,否则计数减一;当计数为0时,将遇到的下一个整数保存到c中,计数重新为1,开始新一轮计数,直到扫描所有的数组元素。

2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释

int Majority(intA[],int n){
  int i,c,count=1;  //c用来保存候选主元素,count用来计数
  c=A[0];
 for(i=1;i<n;i++){
   if(A[i]==c)
     count++;
   else
     if(count>0)
       count--;
     else{
       c=A[i];
       count=1;
     }
 }
  if(count>0)
    for(i=count=0;i<n;i++)
      if(A[i]==c)
        count++;
  if(count>n/2) return c
  else return -1;
}

3)说明你所设计的算法时间复杂度和空间复杂度

时间复杂度为O(n),空间复杂度为O(1

1)给出算法的基本设计思想

要求时间上尽可能高效,因此采用空间换时间的方法。分配一个用于标记的数组B[n]用来记录A中是否出现了1~n中的正整数,B[0]对应正整数1,B[n-1]对应正整数n,初始化B中全部为0.由于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,返回i+1即为结果,此时说明A中未出现的最小正整数1~n之间。若B[i]全部不为0,返回i+1(跳出循环时i=n,i+1=n+1),此时说明A中未出现的最小正整数是n+1

2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释

int findMissMin(int A[],int n){
  int i,*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)
      B[A[i]-1]=1;
  for(i=0;i<n;i++)
    if (B[i]==0) break;
  return i+1;
}

3)说明你所设计的算法时间复杂度和空间复杂度

时间复杂度:O(n)
空间复杂度:O(n)

1)给出算法的基本设计思想

分析。由D=|a-b|+|b—c|+|c—a|>=0有如下结论。
  1.当a=b=c时,距离最小。
  2.其余情况不失一般性,假设a<=b<=c,观察下面的数轴:
  L1=|a-b|
  L2=|b-c|
  L3=|c-a|
  D=|a-b|+|b-c|+|c-a|=L1+L2+L3=2L3
  由D的表达式可知,事实上决定D大小的关键是a和c之间的距离,于是问题就可以简化为每次固定c找一个a,使得L3=|c-a|最小。
  
(1)使用Dmin记录所有已处理的三元组的最小距离,初值为一个足够大的整数
(2)集合S1、S2和S3分别保存在数组A、B、C中。数组的下标变量i=j=k=0,当i<|S1|、j<|S2|且k<|S3|时(|S|表示集合S中的元素个数),循环执行下面的a)~c)。
  a)计算(A[i]、B[j]、C[k])的距离D;(计算D)
  b)若D<Dmin,则Dmin=D;(更新D)
  c)将A[i]、B[j]、C[k]中的最小值的下标+1;(对照分析:最小值a,最大值为c,这里c不变而更新a,试图寻找更小的距离D)
(3)输出Dmin,结束。
  
  

2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释

#define INT_MAX 0x7fffffff		
int abs_(int a){//计算绝对值
  if(a<0) return -a;
  else return a;
}
bool xls_min(int a,int b,int c){//a是否是三个数中的最小值
  if(a<=b&&a<=c) return true;
  return false;
}
int findMinofTrip(int A[],int n,int B[],int m,intC[],int p){
  //D_min用于记录三元组的最小距离,初值赋为INT_MAX
  int i=0,j=0,k=0,D_min=INT_MAX,D;
  while(i<n&&j<m&&k<p&&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(xls_min(A[i],B[j],C[k])) i++;
   else if(xls_min(B[j],C[k],A[i])) j++;
   else k++;
  }
  return D_min;
}

3)说明你所设计的算法时间复杂度和空间复杂度

设n=(|S1|+|S2|+|S3|),时间复杂度为O(n),空间复杂度为O(1)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值