2.1
2.1.1
执行过程如下:
2.1.2
按非升序排序的插入排序:
//插入排序,输入数组A和元素个数n
void insertion_sort(int A[],int n)
{
for(int j=1;j<n;j++)
{
int key=A[j];
int i=j-1;
while(i>=0&&A[i]<key)
{
A[i+1]=A[i];
i--;
}
A[i+1]=key;
}
}
2.1.3
线性查找代码如下:
//线性查找
//输入数组A和元素个数n,以及查找元素v
//输出元素下标,或者不存在返回-1
int find_line(int A[],int n,int v)
{
for(int i=0;i<n;i++)
{
if(A[i]==v)
return i;
}
return -1;
}
证明:
初始化:初始时i=0,这个下标之前不存在元素,自然不存在v,满足条件。
保持:i次迭代时,A[0…i-1]不存在v,说明没有找到,保持循环不变式。
终止:有两种情况,一个是找到A[i]=v,返回i;一个是i>=n,没有找到,返回-1.
其中的循环不变量是A[0…i-1],每次迭代都说明前i个元素没有找到v,想要下一次迭代,必须满足A[i]!=v。如果不满足,说明找到了,直接返回下标。不然如果超出循环,说明不存在,返回-1。算法正确。
2.1.4
二进制加法如下:
//二进制相加
//输入两个保存二进制的数组A,B和二进制位数n,以及保存结果的数组C
//输出相加的二进制,存在结果数组C里面
void add_two(int A[],int B[],int n,int C[])
{
int k=0;//是否有进位
for(int i=n-1;i>=0;i--)
{
C[i+1]=A[i]+B[i]+k;
if(C[i+1]>1)
{
k=C[i+1]/2;
C[i+1]%=2;
}
else
k=0;
}
C[0]=k;//和的最高位
}
2.2
2.2.1
可以表示为
2.2.2
选择排序如下:
//选择排序
//输入数组A和元素个数n
//输出排序结果
void select_sort(int A[],int n)
{
int index,key;//保存中间结果
for(int i=0;i<n-1;i++)
{
index=i;
key=A[i];
for(int j=i;j<n;j++)
{
if(A[j]<key)
{
key=A[j];
index=j;
}
}
int t=A[i];//交换
A[i]=key;
A[index]=t;
}
}
循环不变式
初始化:i=0,此时数组未排序
保持:每次循环结束后保证A[0,i]的前i+1个元素排好序,是前i+1小的元素
终止:前n-1个元素排好序
当前n-1各元素排好序以后,前n-1个最小元素在自己的位置,那么最后一个元素一定是最大元素,不需要再进行比较了。
选择排序的最好和最坏时间都是
2.2.3
平均需要检查个元素,最坏情况需要检查n个元素,最坏和平均情况下时间都是
2.2.4
需要根据具体的数据情况来设计最适合的算法,也就是根据数据倒推算法
2.3
2.3.1
过程如下:
2.3.2
代码如下:
//归并
//输入数组A和下标p,q,r
//输出合并后的数组
void merge(int A[],int p,int q,int r)
{
int n1=q-p+1;
int n2=r-q;
int L[MAXSIZE],R[MAXSIZE];
for(int i=0;i<n1;i++)
L[i]=A[p+i];
for(int i=0;i<n2;i++)
R[i]=A[q+1+i];
int s=0,t=0;//记录位置
int k=0;//原数组的位置
while(s<n1&&t<n2)
{
if(L[s]<=R[t])
{
A[p+k]=L[s];
k++;s++;
}
else
{
A[p+k]=R[t];
k++;t++;
}
}
//处理剩余元素
if(s==n1)//R数组剩余
{
while(t<n2)
{
A[p+k]=R[t];
k++;t++;
}
}
else if(t==n2)//L数组剩余
{
while(s<n1)
{
A[p+k]=L[s];
k++;s++;
}
}
}
2.3.3
证明如下:
- 当n=2时,,满足条件。
- 假设当为n是满足条件,即;
- 当为2*n时,。满足题目要求。
- 综上所述,递归时的解是。
2.3.4
递归实现如下:
//插入排序递归版本
//输入数组A和元素个数n,以及将要排的元素下标index
//输出排序后的数组
void insert_sort(int A[],int n,int index)
{
if(index>=n)//全部排好序
return;
int key=A[index];
for(int i=index-1;i>=0;i--)//从后往前遍历排好序的元素
{
if(A[i]>key)
{
A[i+1]=A[i];
}
else
{
A[i+1]=key;
insert_sort(A,n,index+1);
return;
}
}
A[0]=key;
insert_sort(A,n,index+1);
return;
}
最坏运行时间是
2.3.5
二分查找代码如下:
//二分查找迭代版本
//输入排好序的数组A和元素个数n,查找元素v
//输出查找元素下标,或者不存在返回-1
int binary_sort(int A[],int n,int v)
{
int l=0,r=n-1;
while(l<=r)
{
int mid=(l+r)/2;
if(A[mid]==v)
return mid;
else if(A[mid]>v)
r=mid;
else
l=mid+1;
}
return -1;
}
最坏运行时间表达式如下:
则解得最坏运行时间为。
2.3.6
改进后如下:
//插入排序二分版本
//输入数组A和元素个数n
//输出排序后的数组
void binary_insert_sort(int A[],int n)
{
if(n<=1)//全部排好序
return;
for(int i=1;i<n;i++)
{
int key=A[i];
int l=0,r=i-1;
while(l<=r)
{
int mid=(l+r)/2;
if(A[mid]>=key)
r=mid-1;
else
l=mid+1;
}
for(int j=i-1;j>r;j--)
A[j+1]=A[j];
A[r+1]=key;
}
}
2.3.7
这一题的解答参考了这位的博客https://blog.csdn.net/KongMing07/article/details/80146592
题目要求需要的时间,很明显,如果是乱序的话很难达到要求,同时,排序的时间也要是才行,这就需要快速排序、二分排序和归并排序,这里用上面改进的插入排序实现:
//寻找和为x的两个数
//输入数组A和元素个数n,要求的和x和
//输出和为x的两个数,返回是否找到
bool find_sum(int A[],int n,int x,int &a,int &b)
{
binary_select_sort(A,n);
int l=0,r=n-1;
while(l<r)
{
if(A[l]+A[r]<x)
l++;
else if(A[l]+A[r]>x)
r--;
else
{
a=A[l];b=A[r];
return true;
}
}
return false;
}