资源描述
习题分析
ITAT第二届:
1、 编写一个Java程序要求:开启一个文本文件,一次读取其内的一行文本。令每一行形成一个String,并将读出的String对象置于LinkedList中。请以相反次序印出LinkedList内的所有文本行。 问题分析:1、需要IO流BufferedReader和FileReader类,通过IO流访问文本文件的每一行。2、Java框架中的LinkedList对象存储每一行。知道文本文件读完。3、通过LinkedList类的listIterator(int size)来实现遍历,通过hasPrevious()和previous()来实现逆序输出。
2、 用LinkedList实现一个stack,实现其中的push(),top()和pop()方法;其中push()实现向栈中加入一个元素,top()实现得到栈的最顶元素,pop()实现删除最顶元素。 问题分析:Stack的特征是:先进后出;通过LinkedList类的addLast(obj)方法实现push()方法;通过getLast()方法实现top()方法,通过removeLast()实现pop()方法。
3、 为Thread撰写两个子类,其中一个的run()在启动后取得第二个Thread object reference,然后调用wait()。另一个子类的run()在过了数秒之后调用notifyAll(),唤醒第一个线程,使第一个线程可以印出消息。 问题分析:1、ThreadSon和ThreadMain类实现Thread类。2、通过启动ThreadMain类的线程来调用ThreadSon线性。3、在ThreadSon类中定义ThreadMain类的对象main,通过对main对象的控制(锁旗标)实现运行ThreadSon后在运行ThreadMain类。4、具体实现: public class MainThread extends Thread
{
public void run()
{
sonThread son=new sonThread(this); //定义子线程的对象
son.start(); //在主线程中调用子线程
System.out.println("主线程等待...");
synchronized(this) //如果获得子线程的锁旗标就等待
{
wait();
System.out.println("主线程启动...");
sleep(3000);
System.out.println("主线程休眠3秒后...");
}
System.out.println("主线程结束!");
}
public static void main(String[] args)
{
MainThread main=new MainThread();
main.start();
}
}
class sonThread extends Thread
{
MainThread main=null; //定义主线程的对象
public sonThread(MainThread mian)
{
this.main=mian;
}
public void run()
{
synchronized (this) //获得对象的锁旗标
{
System.out.println("子线程启动...");
sleep(3000);
System.out.println("子线程休眠3秒后...");
}
System.out.println("子线程结束!");
synchronized (main)
{ main.notify(); } //唤醒主线程
}
}
4、 用Linklist实现一个队列quene;实现put()方法向队列中加入一个元素,get()方法得到第一个元素,isEmpty()判断是否为空。 问题分析:Queue的特征:先进先出;put方法和get方法实现通过调用LinkedList类的addList()方法和getFirst()方法;isEmpty方法的实现调用LinkedList类的isEmpty方法。
5、 撰写一个 myString class,其中包含一个String对象,可于构造函数中通过引数来设定初值。加入toString()和concatenate()。后者会将String对象附加于你的内部字符串尾端。请为myString()实现clone()。撰写两个static函数,令它们都接收myString referencex引数并调用x.concatenate(“test”)。但第二个函数会先调用clone()。请测试这两个函数并展示其不同结果。 问题分析:通过两个方法是先concatenate()和clone();通过对两个的调用和clone()方法,就会输出不同的结果。在这个题中考察的是clone()方法;还要注意一个小知识点:String str=str .concat(“test”);String的concat方法将指定字符串连接到此字符串的结尾。但只能将链接后的值赋值给其他字符串对象,不能赋值给str,即使赋值,但str的内容不会发生变化。String str+=”test”; 表示字符串链接,链接后将最新的值赋值给str,因此str的值发生变化了。此题的两个方法的实现:
public static void Method1(MyStringTest MyStr){
System.out.println(MyStr.concatenate("test")); }
public static void Method2(MyStringTest MyStr){ MyStr.clone()).concatenate("test")); }
ITAT第三届
1、 编写一个Java应用程序,计算并输出一维数组(9.8,12,45,67,23,1.98,2.55,45)中的最大值和最小值。 问题分析:方法很多。方法一:通过循环实现输出最大值和最小值。方法二:通过把这些数存放到TreeSet中,输出第一个和最后一个就可以得到最大值和最小值。方法三:就是调用Java集合框架中Collections的max和min方法实现。方法四:通过Aarays类的Sort方法进行排序,然后输出第一个和最后一个就可以实现。
2、 编写一个Java应用程序,该程序使用FileInputStream类,实现从磁盘读取本应用程序源代码文件,并将文件内容显示在屏幕上。 问题分析:通过IO流中的类来实现从文件中读出,在屏幕上现实,具体实现: FileInputStream fis=new FileInputStream(file); BufferedReader br=new BufferedReader(new InputStreamReader(fis)); 通过把FileInputStream封装成InputStreamRead类,然后在封装成BufferedReader类。通过BufferedReader类实现读的操作。 FileInputStream 从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。BufferedReader从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
3、 编写一个Java应用程序,利用RandomAccessFile类,把几个int型整数(1,2,3,4,5,6,7,8,9,10)写入到一个名字为tom.dat文件中,然后按相反顺序读出这些数据并显示在屏幕上。(注意,一个int型数据占4个字节) 问题分析:1、通过RandomAccessFile类的writeInt()和ReadInt()实现把int整数写入到文件中,和从文件中读出。2、通过length()或getFilePointer()和seek(long pos)实现逆序的输出。Seek方法可以设置输输出的顺序。具体代码如下: RandomAccessFile raf=new RandomAccessFile(file, "rw");
for (int i = 1; i <=10; i++) {
raf.writeInt(i);
}
// long getFilePointer()返回此文件中的当前偏移量。
long s=raf.getFilePointer();
for (int i = 1; i <=10; i++) {
raf.seek(s-i*4);
System.out.print(raf.readInt()+" ");
}
4、编写一个Java应用程序,实现如下功能:
1)判断两个字符串是否相同,s1=”you are a student”,s2=”how are you”;
2)判断字符串”22030219851022024”的前缀、后缀是否和某个字符串”220302”相同;
3)按字典顺序比较两个字符串”你”和”我”的大小关系;
4)将数字型字符串”100”和”123.678”转换为数字;
5)将字符串”FEDCBA”存放到数组中,调用for循环读出数组数据显示在屏幕上。
问题分析:通过调用String类的方法实现:依次用到的方法有:startsWith(str2),endsWith(str2)、compareTo(Str)、Integer.parseInt(str1)、charAt(i);
5、编写一个Java应用程序,对用户输入的任意一组字符如{1,3,4,7,2,1,1,5,2},输出其中出现次数最多且数值最大的字符,并显示其出现次数。
问题分析:通过TreeMap对象来实现,对于已经包含在对象中就让其value加1;输出alue相同并且key最大的即可。迭代输出输出次数最多,且最大的方法是:通过迭代比较器key值,如果key比已经存在的key值大,通过比较其实value值,如果value的值比已经存在的值大,就交换其key和value的值,否则啥也不做。其代码:
Iterator itr = hmap.keySet().iterator(); //对key值进行迭代
String str = (String) itr.next(); //把第一个key 付给str
int times = hmap.get(str); //把第一alue付给times
while (itr.hasNext()) //迭代循环
{
String temp = (String) itr.next();
// 如果temp>str
if (pareTo(temp) < 0) //比较下一个的key和str的大小
{
int n = hmap.get(temp); //得到此key的次数
{
if (times <= n) // temp的次数大于或等于str的次数
{ //交换
str = temp;
times = n;
}
}
}
}
6、 编写一个Java应用程序,使用Java的输入输出流技术将Input.txt的内容逐行读出,每读出一行就顺序为其添加行号(从1开始,逐行递增)并写入到另一个文本文件Output.txt中。 问题分析:通过读出文本的每一行,然后在写进文本时,在前面加如“n+"、"+”即可实现,每一次循环,n++即可,用的的流是BufferedReader、BufferedWriter、FileReader、FileWriter这四个类。
7、 编写一个Java应用程序,使用RandomAccessFile流统计Hello.txt中的单词,要求如下:(1)计算全文中共出现了多少个单词(重复的单词只计算一次);(2)统计出有多少个单词只出现了一次;(3)统计并显示出每个单词出现的频率,并将这些单词按出现频率高低顺序显示在一个TextArea中。 问题分析:首先通过IO流中的类实现输出每一行,然后在通过StringTolennl类实现对字符串的分割,分成一个的单词。通过把每一个单词添加到TreeMap中,如果此单词已经在TreeMap中,就让其alue加1;依次循环,直到把所有的单词添加到TtreeMap中。通过输出TreeMap的个数实现统计一共有多少个单词。通过对TreeMap进行对Value进行迭代,当其值等于1就让其加1,就可以实现统计多少个单词只出现一次。通过TreeMap类的对象进行对alue进行迭代,输出让频率大小输出,但是TreeMap对value进行迭代时,是无须的,所有必须实现这样:
//此类是按对象的值进行排序的
class VluesDown implements Comparator
{
public int compare(Object o1, Object o2)
{
Entry<String, Integer> obj1 = (Entry<String, Integer>) o1;
Entry<String, Integer> obj2 = (Entry<String, Integer>) o2;
return obj2.getValue() - obj1.getValue();
}
}
迭代输出:
List list = new LinkedList(tmap.entrySet());
//根据指定比较器产生的顺序对指定列表进行排序
Collections.sort(list, new VluesDown());
Iterator itr = list.iterator();
while (itr.hasNext())
{
Entry<String, Integer> entry = (Entry<String, Integer>) itr.next();
bw.write(entry.getKey() + "\t\t");
bw.write(entry.getValue() + "");
bw.newLine();
}
bw.close();
8、 编写一个Java应用程序,当用户在输入对话框中输入两个日期后(日期格式为YYYYMMDD,如1999年1月12日应输入为19990112),程序将判断两个日期的先后顺序,以及两个日期之间的间隔天数(例如1999年1月1日和1999年1月2日之间的间隔是1天)。 问题分析:通过GregorianCalendar类的进行初始化日期,通过调用该类的父类 Calendar的方法得到该日期一共有多少天。其代码如下:
GregorianCalendar date;
GregorianCalendar date1=new GregorianCalendar(1988,01,02);
GregorianCalendar date2=new GregorianCalendar(1989,01,02);
//得到此日期的天数
int datetime1=(int) (date1.getTimeInMillis()/(1000*60*60*24));
//得到此日期的天数
int datetime2=(int) (date2.getTimeInMillis()/(1000*60*60*24));
通过比较datetime1和datetime2的差值,就可以实现此题的功能。
9、 编写一个Java应用程序,对于给定的一个字符串的集合,格式如: {aaa bbb ccc}, {bbb ddd},{eee fff},{ggg},{ddd hhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例 应输出:{aaa bbb ccc ddd hhh},{eee fff}, {ggg} (1)分析问题,描述你解决这个问题的思路、处理流程,以及算法复杂度。(2)编程实现题目要求的集合合并。(3)描述可能的改进(改进的方向如效果,算法复杂度,性能等等)。 问题分析:1、通过把上面六个的字符串集合添加到LinkedList类的对象中,先把第一个字符串集合分割后都添加到TreeMap对象tmap中,然后对LinkedList迭代,迭代从第二个位置开始,对于每次循环,把得到的字符串进行分割,对于此循环,设置一个标识符,只要对于此次分割的单词在list1中出现,就把此分割的所有单词添加到tmap中。这样就可以实现两个集合的合并。对于所有分割后的单词都没有在tamp中出现,就把此字符串集合添加到list2中。当一轮循环后,需要判断list2中的集合是否有交集。如果有的话再次进行上面的循环。2、对于上面分割字符判断是否有交集,可以形成一个方法,类型为boolean,如果两个此集合和tmap有交集,就返回true,否则就返回false,通过在上个方法中调用此方法就可以判断。3、也可以把此字符串和tmap的字符串进行拆分在添加到tmap中。4、对于list2集合的判断,也可以写个方法,对于此list2的判断,返回值是boolean,同样在上个主方法中进行判断。具体实现代码如下:
public class CollectionJava
{
LinkedList st; // 存储没有交集的集合
LinkedList list;
public void Fun(LinkedList llist)
{
TreeSet set; // 存储有交集的集合
set = new TreeSet();
LinkedList te = new LinkedList();
Iterator litr = llist.iterator();
while (litr.hasNext())
{
String str = (String) litr.next();
StringTokenizer token = new StringTokenizer(str);
if (set.isEmpty()) // 开始为空时
{
while (token.hasMoreTokens())
set.add(token.nextToken());
} else
{
if (Contin(set, str)) // set集合是包含str字符串某个元素
{
while (token.hasMoreTokens())
set.add(token.nextToken());
} else
te.add(str); // 通过set来屏蔽相同的
}
}
list.add(set); // 最后把set对象添加到list对象中
if (Contin2(te)) // 如果st对象的交集不为空,继续调用Fun()函数
{
st.clear(); // 在移除te
Fun(te);
}
else
st = te;
}
// set对象是否含有str字符串的某个元素
public boolean Contin(TreeSet set, String str)
{
boolean flag = false;
StringTokenizer token = new StringTokenizer(str, " ");
while (token.hasMoreTokens())
{
if (set.contains(token.nextToken()))
flag = true;
}
return flag;
}
// 判断list对象的交集是否为空
public boolean Contin2(LinkedList list)
{
TreeSet et = new TreeSet();
int n = 0;
boolean flag = false;
Iterator lit = list.iterator();
while (lit.hasNext())
{
String str = (String) lit.next();
StringTokenizer token = new StringTokenizer(str, "[ ]");
while (token.hasMoreTokens())
{
n++;
et.add(token.nextToken() + "");
}
}
if (et.size() == n)
flag = false;
else
flag = true;
return flag;
}
10、在下图中的九个点上,空出中间的点,其余的点上任意填入数字1至8;1的位置保持·不动,然后移动其余的数字,使1到8顺时针从小到大排列。移动的规则是:只能将数字沿线移向空白的点。请将制作好的源文件保存为“t2.java”。(本题共60分,要求1占20分,要求2占40分)
要求:
(1)分析问题,并描述你的算法设计思想。
(2)编程显示数字移动过程。
问题分析:1、通过ArrayList类的对象可以实现,
通过把1~8的数字添加到ArrayList类的对象中alist中,
然后在把他们对顺序打乱,通过Collections的
Shuffle(alist)的静态方法。并且索引为0的位置保存着0,通过第一位实现图中的中间位置。2、通过查找1的位置,找到之后,通过调整,把1放在索引为1的位置,1后的数字依次放在索引为1的后面,对于1前面的数依次放在最后元素的后面,类似与一个循环队列。3、开始进行移动,通过查找n(2~8),判断n是否在n-1的位置,如果不在,需要进行移动,移动的规则如下:先把n移近索引为0的位置,然后把n-1的索引位置x到n的索引位置y进行移动,把从索引为x的位置上元素移动到索引为y的位置上,依次类推,知道移动到n-1位置,然后把索引为0的位置元素移动到索引为n-1的位置,然后把索引为0的位置重新置为0 。具体代码如下:
public class T2{
LinkedList<Integer> alist;
// 初始化实现把1——8随即的放入图中那个,中间的位置相当于数组的索引0
public T2() {
for (int i = 1; i < 9; i++) {
alist.add(i); // 把i~8添加到alist中
}
Collections.shuffle(alist); // 打乱alist对象的顺序
alist.add(0, 0); // 第0个位置相当与中的位置。用0代表是空的
}
// alist对象中的第一个位置是1
public void SetFirst(){
int first = alist.indexOf(1); // 锁定1的位置
LinkedList<Integer> tem = new LinkedList<Integer>();
ListIterator listitr = alist.listIterator(first);
while (listitr.hasNext())
tem.add((Integer) listitr.next()); // 把1后的元素添加的tem中
for (int i = 1; i < first; i++)
tem.add(alist.get(i)); // 把1之前的元素添加到tem中
tem.add(0, 0); // 第一个位置相当与中的位置。用0代表是空的
alist = tem; // 赋给alist
}
public void Sort(){
this.SetFirst();
int flag = alist.indexOf(1);
for (int n = 2; n < 9; n++){ // 此循环是实现调整2~9的位置
flag++;
int tem = alist.indexOf(n);
if (flag != tem) // flag后面的位置不是tem位置的元素
{ // 把alist.get(tem)先放在索引为0的位置
alist.set(0, alist.get(tem));
for (int i = tem; i >= flag; i--){
// 把i-1的元素放到i位置上
alist.set(i, alist.get(i - 1));
}
alist.set(flag, alist.get(0));
alist.set(0, 0);
}
}
}
第四届ITAT
1、 编写一个Java应用程序,在其中编写一个类,该类封装了一元二次方程共有的属性和功能,即该类有刻画方程系数的3个成员变量以及计算实根的方法。并给出计算实根的过程。 问题分析:1、通过构造函数初始化一元二次方程的三个系数。2、通过一个参数判断方法有没有实根,类型是boolean的.3、计算方程的根,分三种情况:1)两个根相等,2)两个不相等实根,3)没有实根。4)还需要对一元二次方法的二次项的系数进行是否为0进行判断。
2、 编写一个Java应用程序,开启一个文本文件(以本程序源文件为例读取),一次读取其内的一行文本,令每行形成一个String,并将读出的String对象置于LinkedList中,以相反次序显示出LinkedList内的所有内容。 问题分析:见第二届
3、 Windows操作系统自带的计算器是个很方便的小工具,利用Java的GUI编程,实现一个Java GUI计算器应用程序界面,窗口标题为“计算器”,窗口布局如下图所示,在此计算器应用程序中实现“+、-、*、/”运算操作。 问题分析:通过switch进行+、-、*、/,通过对4求模,等于0进行+;等于1进行+;等于2进行*;等于3进行/;代码如下:
switch (op1)
{
case 0:
n1 = a + b;
x = "+";
break;
case 1:
n1 = a - b;
x = "-";
break;
case 2:
n1 = a * b;
x = "*";
break;
case 3:
n1 = a / b;
x = "/";
break;
4、 有500个小朋友拉成一个圆圈,从其中一个小朋友开始依次编号1-500,从1号小朋友开始循环1-3报数,数到3的小朋友就退出。编写一个Java应用程序,计算出最后一个小朋友的号码是多少 ? 问题分析:通过TreeSet的一个对象实现。首先把1—500的整数添加到对象tset中,然后对其进行循环变量,每当输出三次是,就取出这个数,把这个付给tem,循环结束,tem就是所求的结果。上面实现的是1就是第一个小朋友。同样也可以产生一个随机数,把他当作第一小朋友,进来就对他们进行重新排序,实现算法类似于第三届ITAT中的第十个题,实现重新排序后,就可以进行上述的遍历循环。
5、 水仙花数是指其个位、十位、百位三个数的立方和等于这个数本身。编写一个Java应用程序,求出所有水仙花数。 问题分析:首先求出三位数的个位、十位、百位;然后进行判断即可。代码如下: c=num%10;//个位 b=(num/10)%10;//十位 a=num/100; //百位
6、 编写一个Java应用程序,利用RandomAccessFile类往某个文本文件中写入20个整数(0~19),然后从该文件的第12个字节开始,将后面所有的数据(对应写入的整数)读出。 问题分析:此题的分析类似于第三届的第三题。具体实现如下: //写入流
RandomAccessFile raf=new RandomAccessFile("D://raf.java", "rw");
for(int i=0;i<20;i++)
raf.writeInt(i);
//输出流
long len=raf.length();
System.out.println(len);
for(int i=12;i<len/4;i++)
raf.seek(i*4);
int x=raf.readInt();
System.out.println(x);
7、 采用Java 多线程技术,设计实现一个符合生产者和消费者问题的程序。对一个对象(枪膛)进行操作,其最大容量是12颗子弹。生产者线程是一个压入线程,它不断向枪膛中压入子弹;消费者线程是一个射出线程,它不断从枪膛中射出子弹。
要求:
(1)给出分析过程说明。
(2)程序输出,要模拟体现对枪膛的压入和射出操作;
(3)设计程序时应考虑到两个线程的同步问题。 问题分析:1、四个类:子弹类,生成者类、消费者类、主类;2、子弹类:对一些参数的初始化。方法有生成和消费的方法,两个方法主要共享子弹生成的数目。3:生成类:实现对生成方法的调用。4:实现对消费的方法调用。5:生成类和消费类都有一个子弹的对象。对于子弹类的两个主要的方法都用Synchronize休息。具体代码实现如下:
// 对一个对象(枪膛)进行操作,其最大容量是12颗子弹。
class ZiDan
{
int size = 0; // 子弹总量
int number = 0; // 可以子弹
boolean avaiable; // 控制字段压入和射出操作
public ZiDan(int size) // 带参数的构造函数
{
this.size = size;
avaiable = false;
}
// 压入子弹
public synchronized void Push()
{
if (avaiable) // 如果有子弹,等待
wait();
System.out.println("向枪膛中压入子弹 " + (++number));
avaiable = true;
notify();
// 释放对象锁旗标
}
//从枪膛中射出子弹
public synchronized void Pop()
{
if (!avaiable) // 如果没有子弹,等待
{
wait();
}
System.out.println("从枪膛中射出子弹 " + number);
avaiable = false;
notify();
if(number==size)
number++;
}
}
// 生产者线程是一个压入线程,它不断向枪膛中压入子弹;
class Producer extends Thread
{
// 字段
ZiDan zd;
// 构造函数
public Producer(ZiDan zd)
{
this.zd = zd;
}
public void run()
{
while (zd.number < zd.size) // 当子弹的数量小于子弹的总量
zd.Push();
System.out.println("子弹压入结束!");
}
}
// 消费者线程是一个射出线程,它不断从枪膛中射出子弹。
class Consumer extends Thread
{
// 字段
ZiDan zd;
int i = 0;
// 构造函数
public Consumer(ZiDan zd)
{
this.zd = zd;
i = 0;
}
public void run()
{
while (zd.number <= zd.size) // 循环条件:子弹的数量小于总量
zd.Pop();
System.out.println("射出子弹结束!");
}
}
8、某企业为了促销,搞抽奖宣传活动,奖品为新款手机一部,抽奖规则如下:
(1)有n个盒子摆成一圈,盒子按顺时针方向依次编号为0,1,2,……,n-1。手机随 机放在其中一个盒子中。(n为自然数)
(2)从0号盒子开始摸奖,顺时针方向计数,每遇到第m个盒子就摸奖一次。(m为自然数,m<n)
(3)直到重新摸到0号盒子为止。
例如n=5,m=3,那么摸奖经过的盒子编号依次为0,3,1,4,2,0。
请编写一个完整的程序,随机输入n,m(m<n),程序分析手机有没有不被抽中的机会?如果有,概率是多少? (概率=不被抽中的可能数/n)。
问题分析:1、通过产生三个随机数,第一随机数表示盒子的个数,第二随机数表示每次隔几个盒子摸奖,第三个随机数表示奖品放在这个标号的盒子中。2、把n个盒子的序号当作TtreeMap当作key,把从去有奖品的盒子外,所有的盒子的alue都初始化null;有手机的初始化“Mobile”;3、实现对对n个盒子的循环,对此间隔m个盒子,当此键的值等于“Mobile”时,中间,如何循环到n=0时,就结束,没有中奖。具体实现如下:
public class MobileTest
{
int n,m,x;
ArrayList alist;
public MobileTest()
{
alist=new ArrayList();
int tem1,tem2;
tem1=(int)(Math.rando
展开阅读全文