62,616
社区成员
发帖
与我相关
我的任务
分享
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = {12,12,13,14,7};
int i, j, k, low, high, mid, t;
for (i = k = 1; i < a.length; i++) {
low = 0;
high = k - 1;
while (low < high) {
mid = (low + high) / 2;
if (a[mid] >= a[i])
high = mid;
else
low = mid + 1;
}
if ((k == (a[low] < a[i] ? low = k : low)) || a[low] != a[i]) {
t = a[i];
for (j = k - 1; j >= low; j--)
a[j + 1] = a[j];
a[low] = t;
k++;
}
}
for (j = 0; j < k; j++)
System.out.print(a[j]+" ");
}
7 12 13 14
[/quote]
测试了您的代码的各种情况,没有发现问题。完美!
思考了一下这句代码:k == (a[low] < a[i] ? low = k : low) 所展现的意义:
1.要解决第一次进来,相当于没有求low的值,就算a[0]<a[1]也一定会交换位置的问题。
因为第一次进来low=0;i=1;k=1.
若a[low]<a[i],那么把low=k,这时if判断k==k,一定走里面的代码。但是由于我们把low=k了,而这时k=i=1,所以里面的for循环不会
走,同时,位置交换t = a[i];.......a[low] = t; 等于没交换。k++走了。不交换正确,k++正确。
若a[low]=a[i],那么k==low一定不成立,后面的或者条件也不成立,不走if。不交换正确,不k++正确。
若a[low]>a[i],那么k==low一定不成立,但是a[low] != a[i]成立,走if,正常交换,k++。交换正确,k++正确。
2.要解决若 a[i] 的值比前面的值都大,求得的low不对的问题。
若a[low]<a[i],那么把low=k,这时if判断k==k,一定走里面的代码。但是由于我们把low=k了,而这时k的值是已排序不重复数组的长
度,low的值一定是k-1,相当于low++,得到了low的正确位置。位置交换的时候k++走了。交换正确,k++正确。
综上,其实这么写也可以 k == ( a[low] < a[i] ?++ low : 0),关键就是在low的值错误的时候,要手动改变low的值和low的值正确的时候,不要影响后面的判断:(k==0也是一定不会为真的)。所以还可以这么写:low == ( a[low] < a[i] ? low++ : -1).
不过我有一个问题:既然所有的问题都指向low的值求的不正确,那么是否我们是前面的求low的代码
while(___1_____){
mid=(low+high)/2;
if(a[mid]>=a[i]) ______2______;
else low=mid+1;
}
有毛病呢?如果一开始就能够求得正确的low,那么也不会有后面这么弯弯绕绕的代码了呀?
问题应该是真正的完美解决了,最后再提一嘴:这个面试题如果以前没有见过,真的是有人能够在面试的时候做出来吗?我!不!信!太难了。
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = {12,12,13,14,7};
int i, j, k, low, high, mid, t;
for (i = k = 1; i < a.length; i++) {
low = 0;
high = k - 1;
while (low < high) {
mid = (low + high) / 2;
if (a[mid] >= a[i])
high = mid;
else
low = mid + 1;
}
if ((k == (a[low] < a[i] ? low = k : low)) || a[low] != a[i]) {
t = a[i];
for (j = k - 1; j >= low; j--)
a[j + 1] = a[j];
a[low] = t;
k++;
}
}
for (j = 0; j < k; j++)
System.out.print(a[j]+" ");
}
7 12 13 14
当前a为:
12 12 14 13 7
当前a为:
12 12 14 13 7
当前a为:
12 12 14 13 7
当前a为:
12 12 14 13 7
当前a为:
7 12 14 13 7
7 12
用我的代码走的:
当前a为:
12 12 14 13 7
当前a为:
12 12 14 13 7
当前a为:
14 12 14 13 7
当前a为:
13 14 12 13 7
当前a为:
7 13 14 12 7
7 13 14 12
咱们没有一个对的
t = a[i];
for (j = k - 1; j >= low; j--)
a[j + 1] = a[j];
a[low] = t;
所以这个条件(low == i - 1) && (a[low] < a[i])其实只需要写a[low] < a[i] ,
然后就是 k==low = i : low 由于当a[low] < a[i]的时候呢,其实low一定等于i-1,而这时k一定等于low;所以我们把k置为i,就等同于k++;否则k==low,这个一定不成立。
综上分析,这么写:k == (a[low] < a[i] ? low = i : low) 是对的,而且也能填的下空了
不得不提一下这么写: k==low = i 它是一个判断句,但同时也是一个赋值语句,真的厉害,刚看到我还认为这个会报错,语法是错误的呢,学到了。[/quote]
不对,理解错了 应该是:k == ( low = i ) ;low=i 之后,这个表达式的值是i,然后判断k==这个表达式的值,,k的值从来没有++,k一直是原值,但是由于这个时候k确实等于i,所以会走for循环,k在里面++。但是这时low==i了,所以for循环里面 j = k - 1; j >= low 这个条件一定为假,所以for循环其实没有做任何事,t = a[i]; ..... a[low] = t;也无所谓。这才是k的值正确改变和没有发生交换的原因
t = a[i];
for (j = k - 1; j >= low; j--)
a[j + 1] = a[j];
a[low] = t;
所以这个条件(low == i - 1) && (a[low] < a[i])其实只需要写a[low] < a[i] ,
然后就是 k==low = i : low 由于当a[low] < a[i]的时候呢,其实low一定等于i-1,而这时k一定等于low;所以我们把k置为i,就等同于k++;否则k==low,这个一定不成立。
综上分析,这么写:k == (a[low] < a[i] ? low = i : low) 是对的,而且也能填的下空了
不得不提一下这么写: k==low = i 它是一个判断句,但同时也是一个赋值语句,真的厉害,刚看到我还认为这个会报错,语法是错误的呢,学到了。package hashMap;
public class A {
// 2、编写将一维数组a[]中互不相同的数按从小到大顺序重新存于一维数组a[]的程序。
// 二分排序(插入排序的加强)
public static void main(String[] args) {
int a[] = { 13 , 12 ,14 , 15 , 18 ,6, 4 , 3 , 4 , 6, 7 };
printa(a);
int i, j, k, low, high, mid, t;
// i 数组下标
// j 插入时后移用到的下标
// k 已排序的元素个数
// low 二分法的区域下界下标
// high 二分法的区域上界下标
// mid 上下界的一半的下标
// t 用于在后移元素时保存将要被覆盖的那个值
for (i = k = 1; i < a.length; i++) {// 从第1个开始,因为数组第一个元素默认已排
low = 0;
high = k - 1;// 为什么?从0 到k-1下标的是已排序的数组
while (low < high) {
mid = (low + high) / 2;
if (a[mid] >= a[i])// 取得中间的那个数,比当前的数大
high = mid;// 取前半部分
else
low = mid + 1;// 取后半部分
}
// 换位置。 什么情况下不需要换位置?
// 1.low的位置就在i之前的一个 =集合A
// 且
// 2.当前a[i],已经等于啊a[low] ,如 1,2,3,【a[i]=3】,...=集合B
// a&&B
// 所以要交换位置的时候就是!(A&&B)
// !A||!B
// 用集合可以和明显看出来
// 若求得的low=i-1,不让他走循环,但是要让k++
if (k == ((low == i - 1) && (a[low] < a[i]) ? ++low + ++k : k + 1) || a[low] != a[i]) {
t = a[i];
for (j = k - 1; j >= low; j--)// 把所有元素后移一个位置
a[j + 1] = a[j];
a[low] = t;
k++;
}
printa(a);
}
for (j = 0; j < k; j++)// 最后已排序数据的长度,其实就是a.length
System.out.print(a[j] + " ");
}
private static void printa(int[] a) {
System.out.println(" 当前a为: ");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println();
}
}
运行结果:
当前a为:
13 12 14 15 18 6 4 3 4 6 7
当前a为:
12 13 14 15 18 6 4 3 4 6 7
当前a为:
12 13 14 15 18 6 4 3 4 6 7
当前a为:
12 13 14 15 18 6 4 3 4 6 7
当前a为:
12 13 14 15 18 6 4 3 4 6 7
当前a为:
6 12 13 14 15 18 4 3 4 6 7
当前a为:
4 6 12 13 14 15 18 3 4 6 7
当前a为:
3 4 6 12 13 14 15 18 4 6 7
当前a为:
3 4 6 12 13 14 15 18 4 6 7
当前a为:
3 4 6 12 13 14 15 18 4 6 7
当前a为:
3 4 6 7 12 13 14 15 18 6 7
3 4 6 7 12 13 14 15 18
您说得对,其实问题就是要在 (low == i - 1) && (a[low] < a[i]) 的条件下做到两件事:
1.不移位
2.k++
所以我弄了一个三目运算,利用这个三目运算实现上述两个功能 :
k == ((low == i - 1) && (a[low] < a[i]) ? ++low + ++k : k + 1) 。
++low 是为了使得||后面的low==i,故a[low] != a[i]不会满足,循环跳过,
++k是为了把k值+1.
还要注意k==(。。。。)一定不要满足,即||前面的条件一定要为假
如此一来就满足题意了。
测试没问题。
不知道您觉得对不对?
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = { 13 , 12 ,14 , 15 , 18 ,6, 4 , 3 , 4 , 6, 7 };
int i, j, k, low, high, mid, t;
for (i = k = 1; i < a.length; i++) {
low = 0;
high = k - 1;
while (low < high) {
mid = (low + high) / 2;
if (a[mid] >= a[i])
high = mid;
else
low = mid + 1;
}
if ((k == (a[low] < a[i] ? low = i : low)) || a[low] != a[i]) {
t = a[i];
for (j = k - 1; j >= low; j--)
a[j + 1] = a[j];
a[low] = t;
k++;
}
}
for (j = 0; j < k; j++)
System.out.print(a[j]+" ");
}
}
3 4 6 7 12 13 14 15 18
public class A {
public static void main(String[] args) {
int a[] = {15,7,15,6,4,3,4,6,7};
int i, j, k, low, high, mid, t;
for (i = k = 1; i < a.length; i++) {
low = 0;
high = k - 1;
while (low < high) {
mid = (low + high) / 2;
if (a[mid] >= a[i])
high = mid ;
else
low = mid + 1;
}
if (a[high]!=a[i] || a[low] != a[i]) {
t = a[i];
for (j = k -1; j >= low; j--)
a[j + 1] = a[j];
a[low] = t;
k++;
}
}
for (j = 0; j < k; j++)
System.out.print(a[j] + " ");
}
}
运行结果:
3 4 6 7 15
public class A {
public static void main(String[] args) {
int a[] = {15,7,15,6,4,3,4,6,7};
int i, j, k, low, high, mid, t;
for (i = k = 1; i < a.length; i++) {
low = 0;
high = k - 1;
while (low < high) {
mid = (low + high) / 2;
if (a[mid] >= a[i])
high = mid ;
else
low = mid + 1;
}
if (a[high]!=a[i] || a[low] != a[i]) {
t = a[i];
for (j = k -1; j >= low; j--)
a[j + 1] = a[j];
a[low] = t;
k++;
}
}
for (j = 0; j < k; j++)
System.out.print(a[j] + " ");
}
}
运行结果:
3 4 6 7 15
[/quote]
多了这一个判断:if (a[high]!=a[i] || a[low] != a[i]) 会不会导致k++不走了。一旦k++不走了,下面的输出会错,上面的k-1,也不对。您看对不对?
package hashMap;
public class A {
// 2、编写将一维数组a[]中互不相同的数按从小到大顺序重新存于一维数组a[]的程序。
// 二分排序(插入排序的加强)
public static void main(String[] args) {
int a[] = {15,7,15,6,4,3,4,6,7};
printa(a);
int i, j, k, low, high, mid, t;
// i 数组下标
// j 插入时后移用到的下标
// k 已排序的元素个数
// low
// high
// mid
// t 用于在后移元素时保存将要被覆盖的那个值
for (i = k = 1; i < a.length; i++) {// 从第1个开始,因为数组第一个元素默认已排
low = 0;
high = k - 1;//为什么?从0 到k-1下标的是已排序的数组
while (low < high) {
mid = (low + high) / 2;
if (a[mid] >= a[i])//取得中间的那个数,比当前的数大
high = mid ;//取前半部分
else
low = mid + 1;
}
//换位置。 什么情况下不需要换位置?
//1.low的位置就在i之前的一个 =集合A
//且
//2.当前a[i],已经等于啊a[low] ,如 1,2,3,【a[i]=3】,...=集合B
//a&&B
//所以要交换位置的时候就是!(A&&B)
//!A||!B
//用集合可以和明显看出来
//if (low!=i-1 || a[low] != a[i]) {
t = a[i];
for (j = k -1; j >= low; j--)// 把所有元素后移一个位置
a[j + 1] = a[j];
a[low] = t;
k++;
//}
printa(a);
}
for (j = 0; j < k; j++)// 最后已排序数据的长度,其实就是a.length
System.out.print(a[j] + " ");
}
private static void printa(int[] a) {
System.out.println(" 当前a为: ");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println();
}
}
题目好像有问题,其中第三个空应该是不需要的,因为不论怎样都要移动位置,否则不走k++会导致k的值不正确。