一种排序--引发:java两个引用指向同一个对象

地址:http://acm.nyist.net/JudgeOnline/problem.php?pid=8

一种排序

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 3
描述
现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复;还知道这个长方形的宽和长,编号、长、宽都是整数;现在要求按照一下方式排序(默认排序规则都是从小到大);

1.按照编号从小到大排序

2.对于编号相等的长方形,按照长方形的长排序;

3.如果编号和长都相同,按照长方形的宽排序;

4.如果编号、长、宽都相同,就只保留一个长方形用于排序,删除多余的长方形;最后排好序按照指定格式显示所有的长方形;
输入
第一行有一个整数 0<n<10000,表示接下来有n组测试数据;
每一组第一行有一个整数 0<m<1000,表示有m个长方形;
接下来的m行,每一行有三个数 ,第一个数表示长方形的编号,

第二个和第三个数值大的表示长,数值小的表示宽,相等
说明这是一个正方形(数据约定长宽与编号都小于10000);
输出
顺序输出每组数据的所有符合条件的长方形的 编号 长 宽
样例输入
1
8
1 1 1
1 1 1
1 1 2
1 2 1
1 2 2
2 1 1
2 1 2
2 2 1
样例输出
1 1 1
1 2 1
1 2 2
2 1 1
2 2 1

由题目:要注意一点:第二个和第三个数值大的表示长,数值小的表示宽,相等。

需要对长和宽进行处理。

思路:

其实也很简单,就是一种升序的排列,还要涉及到权重,权重(编号>长>宽),只有相等的时候,才需要比较下一个等级。并且,一个尤其重要的是:涉及到交换和移动的时候一定要整体进行。而且测试用例有点坑嗲,如果你交换或移动没有整体性的话,得出的结果和测试用例是一样的。这就导致为什么很多人士wrong answer 的。。---我就是其中一个

第一种方法:(同样是用插入排序,把他写熟了,性能是怎么都好过冒泡排序的)

	//暴力的插入排序,思想很简单,根据权重顺序进行排列,相等的时候,继续比较下一个(权重:编号,长,宽)不过不知道为何wrong answer,感觉思路是没有错的--原来是要整体性交换
	public void insertSortOne(Scanner sc){
		int n=sc.nextInt();
		while(n-->0){
			int m=sc.nextInt();
			int[] numArr=new int[m];
			int[] longArr=new int[m];
			int[] widthArr=new int[m];
			int tmpN,tmpL,tmpW,tmp;
			for(int i=0;i<m;i++){
				tmpN=sc.nextInt();	//得到编号
				tmpL=sc.nextInt();
				tmpW=sc.nextInt();
				if(tmpW>tmpL){			//得到长和宽
					tmp=tmpW;
					tmpW=tmpL;
					tmpL=tmp;
				}
				//插入排序--先实现,后面再优化--交换的时候,要当成一个整体进行交换,不是就会错,而且给出的测试案例特殊,不交换测试案例也是对的。但是肯定是wrong answer
				int j=i;
				while(j>0&&tmpN<numArr[j-1]){	//若相同跳出,插在后一个
					numArr[j]=numArr[j-1];
					longArr[j]=longArr[j-1];
					widthArr[j]=widthArr[j-1];
					j--;
				}
				numArr[j]=tmpN;
				if(j!=0&&numArr[j]==numArr[j-1]){  	//不在数组第一位的时候,且当前和前一个相同时,就比较长
					//对长进行插入排序
					int l=j;
					while(l>0&&tmpL<longArr[l-1]){
						numArr[l]=numArr[l-1];
						longArr[l]=longArr[l-1];
						widthArr[l]=widthArr[l-1];
						l--;
					}
					longArr[l]=tmpL;
					if(l!=0&&longArr[l]==longArr[l-1]){
						//对宽进行排列
						int w=l;
						while(w>0&&tmpW<widthArr[w-1]){
							numArr[w]=numArr[w-1];
							longArr[w]=longArr[w-1];
							widthArr[w]=widthArr[w-1];
							w--;
						}
						widthArr[w]=tmpW;
						if(w!=0&&widthArr[w]==widthArr[w-1]){
							//说明三个都相等,把他去掉
							i--;	//重新填充i,即可
							m--;	//相应把for循环的长度给缩小
						}
					}
					else{
						widthArr[l]=tmpW;
					}
				}
				else{
					longArr[j]=tmpL;
					widthArr[j]=tmpW;
				}
				
			}
			//进行输出结果
			for(int i=0;i<m;i++)
				System.out.println(numArr[i]+" "+longArr[i]+" "+widthArr[i]);
		}
	}

第二中方法:

就是声明一个内部类,将编号,长,宽放进去。通过get,set进行修改,也是一种封装的思想(但是一个开始不是这样的,贪图方便)。尤其是插入排序,一定为涉及到数组对象的移动的。

使用前必须实例化一个对象先:rectangle[i]=new Rectangle();

直接把它写成:rectangle[j]=rectangle[j-1];对象数组存的是一个对象引用,前面这样先,相当于拷贝,即:两个引用指向了同一个对象,无论通过修改那个引用,必定会修改到同一个对象,具体查看:浅拷贝和深拷贝。留个网址(不一定是最好的):http://kuangbaoxu.iteye.com/blog/193222

所以必须做出修改,通过get,set进行赋值,移动 或者用集合,暂时没想到

rectangle[j].setNum(rectangle[j-1].getNum());
rectangle[j].setLeng(rectangle[j-1].getLeng());
rectangle[j].setWidth(rectangle[j-1].getWidth());

附上方法二:

	public void insertSortTwo(Scanner sc){

		int n=sc.nextInt();
		while(n-->0){
			int m=sc.nextInt();
			
			Rectangle[] rectangle=new Rectangle[m];
			int tmpN,tmpL,tmpW,tmp;
			for(int i=0;i<m;i++){
				rectangle[i]=new Rectangle();	//先实例化出一个对象
				tmpN=sc.nextInt();
				tmpL=sc.nextInt();
				tmpW=sc.nextInt();
				if(tmpL<tmpW){		//先得出符合规则的长和宽,编号
					tmp=tmpL;
					tmpL=tmpW;
					tmpW=tmp;
				}
				int j=i;
				while(j>0&&tmpN<rectangle[j-1].num){
//					rectangle[j]=rectangle[j-1];					//涉及到深拷贝和浅拷贝问题,(对象数组的引用到了同一个对象。即:内存中是两个引用指向了同一个对象,
																	//java机制是不会分配完全两个相同的对象的不同空间的,除非有不同(hascode()不同皆可))
					rectangle[j].setNum(rectangle[j-1].getNum());
					rectangle[j].setLeng(rectangle[j-1].getLeng());
					rectangle[j].setWidth(rectangle[j-1].getWidth());
					j--;
				}
				rectangle[j].num=tmpN;
				if(j!=0&&rectangle[j].getNum()==rectangle[j-1].getNum()){
					//编号相同,进行长排序
					int l=j;
					while(l>0&&tmpL<rectangle[l-1].leng){
//						rectangle[l]=rectangle[l-1];
						rectangle[l].setNum(rectangle[l-1].getNum());
						rectangle[l].setLeng(rectangle[l-1].getLeng());
						rectangle[l].setWidth(rectangle[l-1].getWidth());
						l--;
					}
					rectangle[l].leng=tmpL;
					if(l!=0&&rectangle[l].getLeng()==rectangle[l-1].getLeng()){
						//进行宽的排序
						int w=l;
						while(w>0&&tmpW<rectangle[w-1].width){
//							rectangle[w]=rectangle[w-1];
							rectangle[w].setNum(rectangle[w-1].getNum());
							rectangle[w].setLeng(rectangle[w-1].getLeng());
							rectangle[w].setWidth(rectangle[w-1].getWidth());
							w--;
						}
						rectangle[w].width=tmpW;
						if(w!=0&&rectangle[w].getWidth()==rectangle[w-1].getWidth()){
							i--;
							m--;
						}
					}
					else{
						rectangle[l].setWidth(tmpW);
					}
						
				}
				else{	//不同的话,将相应赋值
					rectangle[j].setLeng(tmpL);
					rectangle[j].setWidth(tmpW);
				}
			}
			for(int i=0;i<m;i++)
				System.out.println(rectangle[i].getNum()+" "+rectangle[i].getLeng()+" "+rectangle[i].getWidth());
		}
	}
	class Rectangle{
		private int num,leng,width;

		public int getNum() {
			return num;
		}

		public void setNum(int num) {
			this.num = num;
		}

		public int getLeng() {
			return leng;
		}

		public void setLeng(int leng) {
			this.leng = leng;
		}

		public int getWidth() {
			return width;
		}

		public void setWidth(int width) {
			this.width = width;
		}
		
	}

这题耗时挺长的,主要是纠结怎么错了,并通过这道题发现自己的不足,也是查漏补缺的机会,现在耗时长,以后就会耗时短了。

以上都是wrong answer。还以为对了。不明觉厉

最后附上一个通过的--用的冒泡排序,难道这道题不能用插入排序???

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {
	public static Scanner scanner = new Scanner(new BufferedInputStream(
			System.in));

	public static void main(String[] args) {
		int count = scanner.nextInt();
		for (int i = 0; i < count; i++) {
			int longer = scanner.nextInt();
			int[] num = new int[longer];
			int[] length = new int[longer];
			int[] wide = new int[longer];
			for (int j = 0; j < longer; j++) {
				num[j] = scanner.nextInt();
				length[j] = scanner.nextInt();
				wide[j] = scanner.nextInt();
				if (length[j] < wide[j]) {
					int temp = length[j];
					length[j] = wide[j];
					wide[j] = temp;
				}
			}
			for (int j = 0; j < longer - 1; j++) {
				for (int k = j + 1; k < longer; k++) {
					if (num[j] < num[k]) {
						int temp = num[j];
						num[j] = num[k];
						num[k] = temp;
						temp = length[j];
						length[j] = length[k];
						length[k] = temp;
						temp = wide[j];
						wide[j] = wide[k];
						wide[k] = temp;
					} else if (num[j] == num[k] && length[j] < length[k]) {
						int temp = num[j];
						num[j] = num[k];
						num[k] = temp;
						temp = length[j];
						length[j] = length[k];
						length[k] = temp;
						temp = wide[j];
						wide[j] = wide[k];
						wide[k] = temp;
					} else if (num[j] == num[k] && length[j] == length[k]
							&& wide[j] < wide[k]) {
						int temp = num[j];
						num[j] = num[k];
						num[k] = temp;
						temp = length[j];
						length[j] = length[k];
						length[k] = temp;
						temp = wide[j];
						wide[j] = wide[k];
						wide[k] = temp;
					} else if (num[j] == num[k] && length[j] == length[k]
							&& wide[j] == wide[k]) {
						num[j] = Integer.MAX_VALUE;
					}
				}
			}
			for (int j = longer - 1; j >= 0; j--) {
				if (num[j] != Integer.MAX_VALUE) {
					System.out
							.println(num[j] + " " + length[j] + " " + wide[j]);
				} else {
					continue;
				}
			}
		}
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值