做题练习--归并排序,穷举

本文介绍了几种典型的数据结构与算法实现案例,包括多路归并排序、字符串全排列及组合问题求解等,并探讨了硬币找零问题的不同解决策略。

最近比较闲,抽空练练爪子:

多路归并

voidMergeLines(int*temp,int*A,intleft,intright)
//其中temp是临时存储空间,A是真正的存放数据空间,left是数组的最左下标,right是数组的最右下标。
...{
//先判断些特殊的边界条件
if(right-left<1)
return;
if(right-left==1)
...{
if(A[right]>A[left])
...{
swap(A[right],A[left]);

}

return;
}

intmid=(right-left)/2+left;
MergeLines(
&temp[0],&A[0],left,mid);
MergeLines(
&temp[mid+1],&A[mid+1],0,right-mid-1);
//真正的归并开始(这里可以看做已经做到最后一步)
intk=0;
inti=0,j=mid+1;
while(i<=mid&&j<=right)
...{
if(A[i]>A[j])
...{
temp[k
++]=A[i++];
}

else
...{
temp[k
++]=A[j++];
}

}

if(i>mid)
...{
while(j<=right)
...{
temp[k
++]=A[j++];
}

}

else
...{
while(i<=mid)
...{
temp[k
++]=A[i++];
}

}

//重新将值赋回A数组
for(i=0;i<k;i++)
...{
A[i]
=temp[i];
}

}

使用一个串中相同的字母再生成新串,打印所有的串。比如“abc”有“bac”“bca”....等等。

这段代码的想法是{a,b,c},拿到{a},将{b,c}去递归。如果拿到{b},将{a,c}去递归。

voidAll(stringpre,char*str,intlen)//pre是前缀,str是真正的串,len是串的长度(除去'/0')
//这里注意str必须是一个new出来的字符串数组,不能是字符串常量数组。
//开始的调用可以这样写All("",str,strlen(str));
...{
if(*str=='/0')
return;
if(len==1)
...{
cout
<<pre<<str[0]<<endl;
return;
}

for(inti=0;i<len;i++)
...{
if(i==0)
All(pre
+str[0],&str[1],len-1);
if(i!=0)
...{
swap(str[i],str[
0]);
All(pre
+str[0],&str[1],len-1);
swap(str[i],str[
0]);
}



}


}

上面的函数可以进一步改写:这里的List就是{‘a’,'b'},currentIndex = 0;k = len -1,len = List的元素个数。


voidAll(char*List,intcurrentIndex,intk,intlen)
...{

if(currentIndex==k)
...{
for(inti=0;i<len;i++)
...{
cout
<<List[i];
}

cout
<<endl;
}

else
...{
for(inti=currentIndex;i<=k;i++)
...{
swap(List[currentIndex],List[i]);
All(List,currentIndex
+1,k,len);
swap(List[currentIndex],List[i]);

}

}


}

现在有一张纸币,但是现在有一堆个数无限的硬币(1角,2角,5角),兑换硬币

voidpast(inti)//这里的i是最初的钱的价值(兑换成角,1元就是10角....)不过这里还是使用了穷举...:<
...{
intu=0;
for(intj=0;j<=i;j+=5)
for(intx=0;x<=i;x+=2)
for(intc=0;c<=i;c+=1)
...{
if(j+x+c==i)
...{
cout
<<"<5,2,1>"<<endl;
cout
<<j/5<<","<<x/2<<","<<c<<endl;
u
++;
}

}

}

不过写的代码自我感觉变量命名和函数命名不规范。这的确是今后要大大改进的地方。而且效率还很低。

因为硬币的穷举算法效率很低,所以用背包法重写代码:

如果输入的dest是10角,那么这里的srcSet应该含有10/1个1角,10/2个2角,10/5个5角。currentIndex是srcSet的下标,srcLen是srcSet的大小,subSet是符合条件的数据,num是subSet的集合中现含的元素个数。

intmatch(int*srcSet,intcurrentIndex,intsrcLen,intdest,int*subSet,intnum)
...{
if(currentIndex==srcLen)
return-1;
if(dest-srcSet[currentIndex] < 0)
return -1;
if(dest-srcSet[currentIndex]==0)
...{
subSet[num
++]=srcSet[currentIndex];
cout
<<num<<"numbermatchthedest,theyare:"<<endl;
for(inti=0;i<num;i++)
...{
cout
<<subSet[i]<<"";
}

cout
<<endl;
returnnum;
}

subSet[num]
=srcSet[currentIndex];
intnumber=match(srcSet,currentIndex+1,srcLen,dest-srcSet[currentIndex],subSet,num+1);
if(number<=0)
...{
returnmatch(srcSet,currentIndex+1,srcLen,dest,subSet,num);
}

else
...{
returnmatch(srcSet,currentIndex+1,srcLen,dest,subSet,num);
}

}
但是该算法仍然有的缺陷是最后返回的一定是-1。所以只好在程序运行过程中打印出结果。这里要求数组srcSet是从小到大排列的。虽然算法的复杂度没有降低,但是运行的时间可能会加快。但是在最差情况下,比上面的穷举效率还低。而且多使用了空间。感觉类似于迷宫问题。虽然可以用A*但是最差情况下,比穷举还低。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值