bool DeleteMin(SqList &L,ElemType &min){
if(L.length==0){
printf("顺序表为空\n");
return false;
}
else{
//先找到最小元素的位置
min=L.data[0];
int index=0;//最小元素在数组中的下标
for(int i=1;i<L.length;i++){
if(L.data[i]<min){
min=L.data[i];
index=i;
}
}
/*
if(index == L.length-1){//说明这就是最后一个元素
L.length--;
return true;
}
else{*/
L.data[index]=L.data[L.length-1];//将最后一个元素填充过去
return true;
//}
}
}
bool ReverseList(SqList &L){
if(L.length==0){
printf("表空\n");
return false;
}
Elemtype t;
for(int i=0;i<(L.length/2);i++){
t=L.data[L.length-1-i];
L.data[L.length-1-i]=L.data[i];
L.data[i]=t;
}
return true;
}
用k记录顺序表L中不等于x的元素个数(即需要保存的元素的个数),边扫描L边统计k, 并将不等于x的元素向前移动k个位置,最后修改L的长度
bool DeleteX(SqList &L,Elemtype x){
if(L.length==0){
printf("表空\n");
return false;
}
int k=0;
for(int i=0;i<L.length;i++){
if(L.data[i] != x){
L.data[k]=L.data[i];
k++;
}
}
L.length=k;//@@@
}
这种解法可以不考虑有序表的升序降序问题,但是没有利用有序表的优势
bool DeleteStoT(SqList &L, Elemtype s,Elemtype t){
if(s>=t || L.length==0){
printf("Error\n");
return false;
}
int k=0;
for(int i=0;i<L.length;i++){
if(!(L.data[i] >= s && L.data[i] <= t)){
//不符合删除条件的元素则前移k个位置,最后修改L的长度
L.data[k]=L.data[i];
k++;
}
}
L.length=k;
return true;
}
解法2:但是下面的答案默认所给有序表是升序排列的…
bool DeleteStoT(SqList &L, Elemtype s,Elemtype t){
if(s>=t || L.length==0){
printf("Error\n");
return false;
}
int i,j;
for(i=0;i<L.length && L.data[i]<s;i++);//找到第一个>=s的元素的位置
if(i>=L.length){
return false;//所有元素均
}
for(j=i;j<L.length && L.data[j]<=t;j++);//找到第一个>t的元素的位置
for(;j<L.length;i++,j++){
L.data[i]=L.data[j];
}
L.length=i;
return true;
}
bool DeleteStoT(SqList &L, Elemtype s,Elemtype t){
if(s>=t || L.length==0){
printf("Error\n");
return false;
}
int k=0;
for(int i=0;i<L.length;i++){
if(!(L.data[i] >= s && L.data[i] <= t)){
//不符合删除条件的元素则前移k个位置,最后修改L的长度
L.data[k]=L.data[i];
k++;
}
}
L.length=k;
return true;
}
bool DeleteSame(SqList &L){
if(L.length==0){
printf("Error\n");
return false;
}
int k=0;
for(int i=1;i<L.length;i++){
if(L.data[i] != L.data[k])){//若后面的元素不等与前面的元素则加入k中
L.data[++k]=L.data[i];
}
}
L.length=k+1;//因为k表示数组下标
return true;
}
bool MergeOrderedList(SqList A,SqList B,SqList &C){
if(A.length+B.length > C.maxsize){
return false;
}
int i,j,k;
k=0;
for(i=0,j=0;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[j++];
}
}
while(i<A.length){
C.data[k++]=A[i++];
}
while(j<B.length){
C.data[k++]=B[j++];
}
C.length=k;
return true;
}
bool ExchangeAB(int A[],int m,int n){
int i,j;
i=m-1;
j=m+n-1;
int t;
for(;i>=0;i--,j--){
t=A[i];
A[i]=A[j];
A[j]=t;
}
return true;
}
//折半查找
void FindOrInsert(List &L,Elemtype x){
int low=0,high=L.length-1;
int mid;
while(low < high){
mid=(low+high)/2;
if(L.data[mid] == x)
break;
if(L.data[mid] < x){
low=mid+1;
}else{
high=mid-1;
}
}
if(L.data[mid]==x && mid != L.length-1){
//找到且不是最后一个元素,则和其后面一个元素互换位置
Elemtype t=L.data[mid+1];
L.data[mid+1]=L.data[mid];
L.data[mid]=t;
}
if(low > high){
for(int i=L.length-1; i>high;i--){
A[i+1]=A[i];
}
A[i+1]=x;
A.length++;
}
}
// My solution 和第8题很像,感觉这种解决方案更优秀
#include
bool ExchangeAB(int A[],int m,int n){
int i,j;
i=m-1;
j=m+n-1;
int t;
for(;i>=0;i--,j--){
t=A[i];
A[i]=A[j];
A[j]=t;
}
return true;
}
int main(){
int a[10]={1,2,3,4,5,6,7,8,9,10};
ExchangeAB(a,4,6);
for(int i=0;i<10;i++){
printf("%d ",a[i]);
}
}
官方答案
- 算法的基本思想,可将这个问题视为把数组ab转换为数组ba(a代表数组的前p个元素,b代表数组中余下的n-p个元素),先将a逆置,再将b逆置,然后将上面得到的结果整体逆置
- 代码
- 时间复杂度O(n),空间复杂度O(1)
void Reverse(int R[], int from, int to){
int i,temp;
for(i=0;i <(to-from+1)/2;i++){
temp=R[i+from];
R[i+from]=R[to-i];
R[to-i]=temp;
}
}
void Converse(int R[], int n, int p){
if(p>=n){
p=p%n;
}
Reverse(R,0,p-1);
Reverse(R,p,n-2);
Reverse(R,0,n-1);
}
#include
int M_Search(int A[],int B[],int n){
int s1=0,d1=n-1,s2=0,d2=n-1;
int m1,m2;
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;
d2=m2;
}else{
s1=m1+1;
d2=m2;
}
}
else{//A[m1]>B[m2]
if((s2+d2)%2==0){
s2=m2;
d1=m1;
}else{
d1=m1;
s2=m2+1;
}
}
}
return A[s1]<B[s2]?A[s1]:B[s2];
}
int main(){
int a[]={11,13,15,17,19};
int b[]={2,4,5,8,20};
int len = sizeof(a)/sizeof(int);
printf("len = %d\n\n",len);
int mid = M_Search(a,b,len);
printf("%d",mid);
return 0;
}
记主元素的为p
因为候选主元素的个数要大于总数的一半,即 >= n/2+1. 所以如果存在主元素的话它的count一定是>1。分析如下:
- 假设总数为偶数个,则候选主元素的count在最坏的情况下是候选主元素均匀分布在数组中,则又因为是总数是偶数个且主元素个数要>= n/2+1,所以最坏情况下必定p在数组中间隔一个分布一个且总有一个位置是有两个连续的p在一起的,所以最坏情况下count也必定大于1 。
- 假设总数是奇数个,则最坏情况下m是间隔一个分布一个的,且数组的头尾都是m,所以这种最坏情况下count也必定大于1 。
- 综上,可以用count这个巧妙的方法来判断是否有主元素。主要是要注意到要求主元素的个数要大于总数的一半,然后利用这个条件想出来的特征。
4.当然,主元素必定有count>=1; 但是count>=1却不一定有主元素,所以最后还要统计一下这个count>=1的元素到底有多少个,是否>=n/2+1;
#include
int MainElement(int A[],int n){
int e,count=1;
e=A[0];
for(int i=0;i<n;i++){
if(A[i]==e){
count++;
}
else{
if(count > 0){
count--;
}
else{
e=A[i];
count=1;
}
}
}
if(count > 0){
count =0;
for(int i=0;i<n;i++){
if(A[i]==e){
count++;
}
}
}
if(count > n/2 ){
return e;
}
return -1;
}
int main(){
int a[8]={0,5,5,3,5,7,5,5};
int b[8]={0,5,5,3,5,1,5,7};
int maina=MainElement(a,8);
int mainb=MainElement(b,8);
printf("maina=%d\n\nmainb=%d\n\n",maina,mainb);
return 0;
}
数组元素的个数为n, 从1开始排查到n, 如果一旦有没查到的就说明找到了,但是时间复杂度为O(n^2)
#include
int MinInteger(int A[],int n){
int i,j;
for(i=1;i<=n;i++){
int flag=0;
for(j=0;j<n;j++){
if(i == A[j]){
flag=1;//说明找到与i相同的了
break;
}
}
if(j==n && flag==0){//如果找到最后一个还没找到和i相同的A[j],退出循环
if(i <= n)
return i;
else
return i+1;
}
}
}
int main(){
int a[8]={1,2,3,4,5,6,8,7};
int b[8]={0,5,5,3,5,1,5,7};
int x=MinInteger(a,8);
int y=MinInteger(b,8);
printf("x=%d\n\ny=%d\n\n",x,y);
return 0;
}
标准答案
memset函数按字节对内存块进行初始化,所以不能用它将int数组初始化为0和-1之外的其他值(除非该值高字节和低字节相同)
以空间换时间
#include
#include
#include
int MinInteger(int A[],int n){
int i,*B;
B=(int*)malloc(sizeof(int) * n);
memset(B,0,sizeof(int)*n);
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;
}
int main(){
int a[8]={1,2,3,4,5,6,8,7};
int b[8]={0,5,5,3,5,1,5,7};
int x=MinInteger(a,8);
int y=MinInteger(b,8);
printf("x=%d\n\ny=%d\n\n",x,y);
return 0;
}
暴力求解
#include
#include
#include
int MinDistance(int A[],int a,int B[],int b,int C[],int c){
int mins=abs(A[0]-B[0])+abs(A[0]-C[0])+abs(B[0]-C[0]);
int group[3]={A[0],B[0],C[0]};
int sum;
for(int i=0;i<a;i++)
for(int j=0;j<b;j++)
for(int k=0;k<c;k++){
sum=abs(A[i]-B[j])+abs(A[i]-C[k])+abs(C[k]-B[j]);
if(sum<mins){
mins=sum;
group[0]=A[i];
group[1]=B[j];
group[2]=C[k];
}
}
printf("tuple is: ");
for(int i=0;i<3;i++)
printf("%d ",group[i]);
return mins;
}
int main(){
int S1[3]={-1,0,9};
int S2[4]={-25,-10,10,11};
int S3[5]={2,9,17,30,41};
int d=MinDistance(S1,3,S2,4,S3,5);
printf("\n");
printf("%d\n",d);
return 0;
}
标准答案:
为啥要把最小值的下标+1, 因为如果把非最小值的下标+1,则得到的Distance只会比原来的更大。
#include
#include
#include
bool isMin(int a,int b,int c){//a是否为最小的那个
if(a<=b && a<=c)
return true;
else
return false;
}
int MinDistance(int A[],int a,int B[],int b,int C[],int c){
int group[3]={A[0],B[0],C[0]};
int i,j,k,d;
int mind=abs(A[0]-B[0])+abs(A[0]-C[0])+abs(B[0]-C[0]);
i=j=k=0;
for(;i<a && j<b && k<c;){
d=abs(A[i]-B[j])+abs(A[i]-C[k])+abs(B[j]-C[k]);
if(d < mind){
mind = d;
group[0]=A[i];group[1]=B[j];group[2]=C[k];
}
if(isMin(A[i],B[j],C[k])){//如果A[i]为三个中最小的
i++;
}
else if(isMin(B[j],C[k],A[i])){
j++;
}
else{
k++;
}
}
printf("tuple is: ");
for(int p=0;p<3;p++){
printf("%d ",group[p]);
}
printf("\n");
return mind;
}
int main(){
int S1[3]={-1,0,9};
int S2[4]={-25,-10,10,11};
int S3[5]={2,9,17,30,41};
int d=MinDistance(S1,3,S2,4,S3,5);
printf("\n");
printf("%d\n",d);
return 0;
}