数据结构(暑假篇7.17)

本文详细解析了一种求解最大子序列和的算法,并通过示例代码展示了如何找到最大子序列及其首尾元素。此外,还介绍了二分查找算法的具体实现及细节处理。

Maximum Subsequence Sum

#include<iostream>
using namespace std;
int main()
{
 int n;
 while(cin>>n)
 {
  int list[n];
  for(int i=0;i<n;i++)
  cin>>list[i];
  
  int flag=0,first=0,end=0;
  int max=-1,sum=0;//max=-1判别全负和部分负数部分0 两种情况 
  for(int i=0;i<n;i++)
  {
   sum+=list[i];
       if(sum<0)
   {
    sum=0;
    flag=i+1;
   }
         else if(sum>max)
   {
    max=sum;
    end=i;
    first=flag;
   } 
   
  }
      if(max<0) 
     cout<<0<<" "<<list[0]<<" "<<list[n-1]<<endl;
    else if(max>=0)
     cout<<max<<" "<<list[first]<<" "<<list[end]<<endl;
 }
}

比起前一篇的算法四,此题还要求输出对应子列和的第一个数和最后一个数,如果有多种相同答案,取第一种。同时若数组全为负,则输出0,第一个元素,最后一个元素。
首先在于max值的设定,此题中应让max=-1,若数组全为负数则进入max<0时的if判断语句;若数组为部分负数部分为0,那么显然正确答案应该为0,0,0,此时max=0,进入对应的if语句。
另外一点的区别在于,当sum=0时,先将下一个下标即i+1赋给flag,再下一次循环中若sum>max,才将flag赋给first完成第一个元素的初始化。而end的查找则比较简单,只要当此循环中sum>max,就更新end为当前的i。
还有一点在于first,end是取对应的下标还是对应的值,刚开始时我取的对应的值,对应的代码如下:

#include<iostream>
using namespace std;
int main()
{
 int n;
 while(cin>>n)
 {
  int list[n];
  for(int i=0;i<n;i++)
  cin>>list[i];
    int flag=0,first=0,end=0;
  int max=-1,sum=0;//max=-1判别全负和部分负数部分0 两种情况 
  for(int i=0;i<n;i++)
  {
   sum+=list[i];
        
    if(sum<0)
   {
    sum=0;
    flag=list[i+1];
   }
         else if(sum>max)
   {
    max=sum;
    end=list[i];
    first=flag;
   }
   
  }
      if(max<0) 
     cout<<0<<" "<<list[0]<<" "<<list[n-1]<<endl;
    else if(max>=0)
     cout<<max<<" "<<first<<" "<<end<<endl;
 
     
 }
}

那么在只有一个正数的情况下,如
5
1 -2 -3 -4 -5
输出的结果为1 0 1,显然是不对的。因为在这种情况下first的值并未更新,输出的只是初始化的值0。
而使用对应的下标输出的则是list[0],则为正确的结果。
PS:细节真的真的很重要啊!!!

复杂度3 二分查找

题目部分提供的代码

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10
#define NotFound 0
typedef int ElementType;

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 保存线性表中最后一个元素的位置 */
};
List ReadInput(); /* 裁判实现,细节不表。元素从下标1开始存储 */
Position BinarySearch( List L, ElementType X );

int main()
{
    List L;
    ElementType X;
    Position P;

    L = ReadInput();
    scanf("%d", &X);
    P = BinarySearch( L, X );
    printf("%d\n", P);

    return 0;
}

/* 你的代码将被嵌在这里 */

函数代码

Position BinarySearch( List L, ElementType X )
{
    int p=0;
    int l=L->Last;
    int i=(1+l)/2;
    for(int j=0;j<(1+l)/2;j++)
    {
        if(X==L->Data[i])
        {
            p=i;
            return p;
        }
        else if(X==L->Data[l])
        {
            p=l;
            return p;
        }
        else if(X>L->Data[i])
        {
                    i=(l+i)/2;
        }
        else if(X<L->Data[i])
        {
         i=(i+1)/2;
  }
    }
    return NotFound; 
}

首先要注意的是元素从下标1开始存储,这就意味着最开始中间的元素是(1+l)/2,l为线性表中最后一个元素的位置(别问我为什么要用跟1这么像的l…)
显然二分查找的最大次数为(1+l)/2,作为循环的限制条件,接着判断X在线性表中的位置。第一个if语句很简单,判断X与当前的中间值是否相等,第二个if语句(我当时没有想到,看了大佬的代码才发现这一点,佩服佩服。)是判断如果X是否在末尾,即L->Data[l]这个位置上。那么为什么要单独判断末尾呢?
可以举一个简单的例子,比如有5个数,分别为
7 11 15 21 23 ,对应的下标为
1 2 3 4 5
如果我们要查找X=23,那么第一步判断X与L->Date[3]是否相等,发现X>15,下一步判断X与L->Date[(3+5)/2]即L->Date[4]的大小,发现X>21,下一步就是关键所在了,L->Data[(4+5)/2]即L->Data[4],会发现X还是和21比较,因为int的除法(4+5)/2是等于4的,然后循坏结束,返回NotFound,因此末尾需要单独判断。而开头则不会出现这种情况,因为(1+2)/2等于1。
后面的判断就很简单了,如果X>L->Date[i],那么 i=(l+i)/2,即判断右半部分;如果XData[i],那么i=(i+1)/2,即判断左半部分。按此循环直到找到X的下标并返回,或者没有找到返回NotFound。
虽然今天后面还看了对数组,链表的查找,插入,删除的操作,可是今天已经不想再看代码了!!!剩余的部分等明天补上吧。
上午稍微学习了一点Python,还停留在基本的概念阶段,路漫漫其修远兮啊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值