20165312 2017-2018-2 第十周课下补做
课上没有做完实验,还是对链表的知识不够熟悉。下课之后我又重新看了一遍第十五章,发现了许多自己遗漏的知识点,同时找到了娄老师的Java Collections API和泛型这篇博客,里面也有对链表的详细讲解。
一、教材十五章代码分析
代码分析有的是以注释的形式写出,对整个代码的理解是写在前面的
1.p442-443 Example15_1.java
Cone.java
此类不关心怎么样计算面积,计算面积由后面的类完成,只需调用即可,只关心计算体积。
public class Cone<E> {
double height;
E bottom; //用泛型类E声明对象bottom
public Cone(E b) { //参数b是泛型类型
bottom = b;
}
public void setHeight(double h) { //此方法给高height赋值
height = h;
}
public double computerVolume() { //计算体积的方法
String s = bottom.toString();//泛型变量只能调用从Object类继承的或重写的方法
double area = Double.parseDouble(s); //将string类型转换成double型
return 1.0 / 3.0 * area * height; //计算体积
}
}
Rect.java
public class Rect { //计算方形面积的类
double sideA, sideB, area;
Rect(double a, double b) { //构造方法将a,b值传给sideA,sideB
sideA = a;
sideB = b;
}
public String toString() {//泛型类中的泛型变量bottom只能调用Object类中的方法,Rect类重写了toString()方法
area = sideA * sideB; //计算面积
return "" + area;
}
}
Circle.java
public class Circle {//计算圆形面积的类
double area, radius;
Circle(double r) {//构造方法将r值传给radius
radius = r;
}
public String toString() { //泛型类中的泛型变量bottom只能调用Object类中的方法,Circle类重写Object类的toString()方法
area = radius * radius * Math.PI;//计算面积,Math.PI为圆周率
return "" + area;
}
}
Example15_1.java
public class Example15_1 {
public static void main(String args[]) {
Circle circle = new Circle(10);
Cone<Circle> coneOne = new Cone<Circle>(circle);//创建一个(圆)锥对象
coneOne.setHeight(16);//调用Cone类中setHeight()方法,将高设为16
System.out.println(coneOne.computerVolume());//调用Cone类中computerVolume()方法,计算体积;computerVolume()方法调用Circle类中的toString()方法,计算面积
Rect rect = new Rect(15, 23);
Cone<Rect> coneTwo = new Cone<Rect>(rect);//创建一个(方)锥对象
coneTwo.setHeight(98);
System.out.println(coneTwo.computerVolume());
//下面方锥体积和上面计算圆锥体积的道理相同
}
}
2.p446 Example15_2.java
例子2比较了使用迭代器遍历链表和get(int Index)
方法遍历链表所用的时间,由于LinkedList的存储结构不是顺序结构,链表调用get(int Index)
方法的速度慢,由于迭代器遍历链表中的一个结点时,同时也得到待遍历的后继对象的引用,所以迭代器的速度较快。
import java.util.*;
public class Example15_2 {
public static void main(String args[]) {
List<String> list = new LinkedList<String>();//创建链表list
for (int i = 0; i <= 60096; i++) {
list.add("speed" + i);//添加结点
}
Iterator<String> iter = list.iterator();//创建迭代器iter
long starttime = System.currentTimeMillis();//获取当前时间
while (iter.hasNext()) {//hasNext()此方法检查链表中是否还有结点
String te = iter.next();//next()方法获取下一个结点
}
long endTime = System.currentTimeMillis();//获取遍历完链表的时间
long result = endTime - starttime;//时间差代表遍历链表的时间
System.out.println("使用迭代器遍历集合所用时间:" + result + "毫秒");
starttime = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {//list.size()为链表结点数
String te = list.get(i);//list.get()依次得到链表中的结点数据
}
endTime = System.currentTimeMillis();
result = endTime - starttime;
System.out.println("使用get方法遍历集合所用时间:" + result + "毫秒");
}
}
3.p447 Example15_3.java
JDK1.5之前没有泛型的LinkedList类,LinkedList mylist = new LinkedList();
创建一个链表对象,mylist链表可以使用get()获取一个结点中的对象,但那是要使用类型转换运算转换回原来的类型。Java泛型的主要目的就是可以建立具有类型安全的集合框架,可以不必进行类型转换。Example15_3.java就是使用原来的方法,和Example15_2.java有一个比较而言吧。。
import java.util.*;
public class Example15_3 {
public static void main(String args[]) {
LinkedList mylist = new LinkedList();//创建链表对象
mylist.add("你"); //链表中的第一个节点
mylist.add("好"); //链表中的第二个节点
int number = mylist.size(); //获取链表的长度
for (int i = 0; i < number; i++) {
String temp = (String) mylist.get(i); //必须强制转换取出的数据
System.out.println("第" + i + "节点中的数据:" + temp);
}
Iterator iter = mylist.iterator();
while (iter.hasNext()) {
String te = (String) iter.next(); //必须强制转换取出的数据
System.out.println(te);
//hasNext()方法和next()方法在前面解释过了
}
}
}
4.p448-449 Example15_4.java
这一个例子实现了链表中的排序和查找
public static sort(List<E>list)
将list中的元素按照升序排列int binarySearch(List<T>list,T key,CompareTo<T> c)
使用折半查找list中是否含有和参数key相同的元素
import java.util.*;
class Student implements Comparable {//Student类通过实现Comparable接口规定该类的对象的大小关系
int height = 0;
String name;
Student(String n, int h) {
name = n;
height = h;
}
public int compareTo(Object b) { // 两个Student对象相等当且仅当二者的height值相等
Student st = (Student) b;
return (this.height - st.height);
}
}
public class Example15_4 {
public static void main(String args[]) {
List<Student> list = new LinkedList<Student>();//创建链表list
list.add(new Student("张三", 188));
list.add(new Student("李四", 178));
list.add(new Student("周五", 198));//向链表中添加3个Student对象
Iterator<Student> iter = list.iterator();//创建迭代器
System.out.println("排序前,链表中的数据");
while (iter.hasNext()) {
Student stu = iter.next();//创建Student对象stu存放结点的数据
System.out.println(stu.name + "身高:" + stu.height);//调用成员变量
}
Collections.sort(list);//Collections类提供用于排序和查找的方法
System.out.println("排序后,链表中的数据");
iter = list.iterator();//再次创建迭代器
while (iter.hasNext()) {
Student stu = iter.next();
System.out.println(stu.name + "身高:" + stu.height);
}
Student zhaoLin = new Student("zhao xiao lin", 178);
int index = Collections.binarySearch(list, zhaoLin, null);//查找
if (index >= 0) {//没有找到index=-1,找到index>=0
System.out.println(zhaoLin.name + "和链表中" + list.get(index).name + "身高相同");
}
}
}
5.p449-450 Example15_5.java
例子5主要使用了链表的重新排列和旋转
public static void shuffle(List<E> list)
将list中的数据按洗牌算法重新随机排列static void rotate(List<E>list,int distance)
旋转list中的数据public static void reverse(List<E> list)
翻转list中的数据
import java.util.*;
public class Example15_5 {
public static void main(String args[]) {
List<Integer> list = new LinkedList<Integer>();//创建链表
for (int i = 10; i <= 50; i = i + 10)
list.add(new Integer(i));//添加结点
System.out.println("洗牌前,链表中的数据");
Iterator<Integer> iter = list.iterator();//创建迭代器
while (iter.hasNext()) {
Integer n = iter.next();
System.out.printf("%d ", n.intValue());//输出下一下int类型的值
}
Collections.shuffle(list);//重新随机排列
System.out.printf("
洗牌后,链表中的数据
");
iter = list.iterator();
while (iter.hasNext()) {
Integer n = iter.next();
System.out.printf("%d ", n.intValue());
}
System.out.printf("
再向右旋转1次后,链表中的数据
");
Collections.rotate(list, 1);//向右旋转一次
iter = list.iterator();
while (iter.hasNext()) {
Integer n = iter.next();
System.out.printf("%d ", n.intValue());
}
}
}
6.p451 Example15_6.java
本例子利用堆栈实现了递归,节省了内存的开销
import java.util.*;
public class Example15_6 {
public static void main(String args[]) {
Stack<Integer> stack = new Stack<Integer>();//建立一个堆栈对象
stack.push(new Integer(1));//压栈,第一项为1
stack.push(new Integer(1));//压栈,第二项为1
int k = 1;
while (k <= 10) {//实现Fibonacci整数序列的前12项
for (int i = 1; i <= 2; i++) {
Integer F1 = stack.pop();//取出栈顶对象
int f1 = F1.intValue();//得到对象的int值
Integer F2 = stack.pop();//取出栈顶对象
int f2 = F2.intValue();//得到对象的int值
Integer temp = new Integer(f1 + f2);//创建f1和f2之和的对象
System.out.println("" + temp.toString());
stack.push(temp);//压栈
stack.push(F2);//将刚才后取出的对象压栈
k++;//实现递归循环
}
}
}
}
7.p453-454 WorldPolice.java
经常需要进行查找的数据可以采用散列映射来储存这样的数据,为数据指定一个查找他的关键字,然后按着键/值对,将关键字和数据一并存入散列映射中。这个例子就是以文本框输出的形式,查询一个汉英词典中是否有这个英文单词,输入英文单词,若有则输出中文解释。与散列映射相关的是WorldPolice.java,我主要分析了这个类的使用。
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.*;
public class WordPolice implements ActionListener {
JTextField showText;
HashMap<String, String> hashtable;//创建散列映射对象
File file = new File("word.txt"); //创建文件对象
Scanner sc = null;
WordPolice() {
hashtable = new HashMap<String, String>();
try {
sc = new Scanner(file);//使用Scanner解析word.txt中的单词
while (sc.hasNext()) {
String englishWord = sc.next();
String chineseWord = sc.next();
//根据word.txt文件可知先是英文单词才是汉语
hashtable.put(englishWord, chineseWord);
//将英文单词、汉语作为键/值对储存在散列映射中
}
} catch (Exception e) {
}
}
public void setJTextField(JTextField showText) {
this.showText = showText;
}
public void actionPerformed(ActionEvent e) {
String englishWord = e.getActionCommand();
if (hashtable.containsKey(englishWord))//若有使用englishWord这个键的键/值对 {
String chineseWord = hashtable.get(englishWord);
//返回使用englishWorld键所对应的值
showText.setText(chineseWord);
//将值输出
} else {
showText.setText("没有此单词");
}
}
}
8.p455-456 Example15_8.java
这个例子创建了树集并向其中添加了结点,并按照english的大小进行了排序。
import java.util.*;
class Student implements Comparable {
//Student类通过实现Comparable接口规定按english确定大小关系
int english = 0;
String name;
Student(int english, String name) {
this.name = name;
this.english = english;
}
public int compareTo(Object b) {
Student st = (Student) b;
return (this.english - st.english);
}
}
public class Example15_8 {
public static void main(String args[]) {
TreeSet<Student> mytree = new TreeSet<Student>();
//创建树集对象
Student st1, st2, st3, st4;
st1 = new Student(90, "赵一");
st2 = new Student(66, "钱二");
st3 = new Student(86, "孙三");
st4 = new Student(76, "李四");
mytree.add(st1);
//以上几句代码可以简写为mytree.add(new Student(90,"赵一"));
mytree.add(st2);
mytree.add(st3);
mytree.add(st4);
Iterator<Student> te = mytree.iterator();//创建迭代器
while (te.hasNext()) {
Student stu = te.next();
System.out.println("" + stu.name + " " + stu.english);
//依次输出排序好的结点
}
}
}
9.p455-456 Example15_9.java
这个例子创建了树映射,并且按照英语成绩和数学成绩排序的。树映射和树集不同的是树映射保证结点是按照结点中的关键字升序排列。
import java.util.*;
class StudentKey implements Comparable {
//StudentKey类通过实现Comparable接口规定按关键字进行排序
double d = 0;
StudentKey(double d) {
this.d = d;
}
public int compareTo(Object b) {
StudentKey st = (StudentKey) b;
if ((this.d - st.d) == 0)
return -1;
else
return (int) ((this.d - st.d) * 1000);
}
}
class Student {
String name = null;
double math, english;
Student(String s, double m, double e) {
name = s;
math = m;
english = e;
}
}
public class Example15_9 {
public static void main(String args[]) {
TreeMap<StudentKey, Student> treemap = new TreeMap<StudentKey, Student>();
//创建一个树映射,StudentKey为关键字,Student为数值
String str[] = {"赵一", "钱二", "孙三", "李四"};
double math[] = {89, 45, 78, 76};
double english[] = {67, 66, 90, 56};
Student student[] = new Student[4];
for (int k = 0; k < student.length; k++) {
student[k] = new Student(str[k], math[k], english[k]);
}
StudentKey key[] = new StudentKey[4];
for (int k = 0; k < key.length; k++) {
key[k] = new StudentKey(student[k].math); //关键字按数学成绩排列大小
}
for (int k = 0; k < student.length; k++) {
treemap.put(key[k], student[k]);//向树映射中添加键/值对
}
int number = treemap.size();//返回树映射中的键/值对个数
System.out.println("树映射中有" + number + "个对象,按数学成绩排序:");
Collection<Student> collection = treemap.values();
Iterator<Student> iter = collection.iterator();//创建迭代器
while (iter.hasNext()) {
Student stu = iter.next();
System.out.println("姓名 " + stu.name + " 数学 " + stu.math);
}
treemap.clear();//清空树映射,为下一轮排序进行准备
for (int k = 0; k < key.length; k++) {
key[k] = new StudentKey(student[k].english);//关键字按英语成绩排列大小
}
for (int k = 0; k < student.length; k++) {
treemap.put(key[k], student[k]);
}
number = treemap.size();
System.out.println("树映射中有" + number + "个对象:按英语成绩排序:");
collection = treemap.values();
iter = collection.iterator();
while (iter.hasNext()) {
Student stu = (Student) iter.next();
System.out.println("姓名 " + stu.name + " 英语 " + stu.english);
}
//按照英语成绩排序和按照数学成绩排序类似,只是更换了关键字
}
}
10.p458-459 Example15_10.java
import java.util.*;
public class Example15_10 {
public static void main(String args[]) {
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
list.add(i); //自动装箱,实际添加到list中的是new Integer(i)。
}
for (int k = list.size() - 1; k >= 0; k--) {
int m = list.get(k); //自动拆箱,获取Integer对象中的int型数据
System.out.printf("%3d", m);
}
}
}
list.add(i);
实现了自动装箱,若没有这项功能,原来应该是list.add(Integer(i))
int m = list.get(k)
实现了自动拆箱,原来应该是:
Integer M = list.get(k);
int m = M.intValue();
二、相关知识点总结
- 链表
- 创建空链表:
LinkedList<String> mylist = new LinkedList<String>();
- 使用
add(E obj)
方法依次增加节点 - 使用
get(int index)
方法遍历链表 - 排序与查找
- 升序排序:
public static sort(List<E> list)
- 折半法查找:
int binarySearch(List<T> list,T key,CompareTo<T> c)
- 升序排序:
- 链表中插入数据:
list.add("xx");
- 创建空链表:
- 树集:TreeSet 树映射:TreeMap
- 使用
Comparator public int compare(java.lang.Object o1, java.lang.Object o2)
如果 o1 和 o2相等,compare返回0;如果o1小于o2,它返回一个负整数;如果o1大于o2,返回一个正整数。
三、第十五章课后练习
1.使用堆栈结构输出an的若干项,其中an=2an-1+2an-2,a1=3,a2=8。
- 代码
import java.util.*;
public class DuiZhan {
public static void main(String args[]) {
Stack<Integer> stack = new Stack<Integer>();//建立一个堆栈对象
stack.push(8);
stack.push(3);
int k = 1;
while (k <= 10) {
for (int i = 1; i <= 2; i++) {
int f1 = stack.pop();
int f2 = stack.pop();
Integer temp = 2*(f1 + f2);
System.out.println("" + temp.toString());
stack.push(temp);
stack.push(f2);
k++;
}
}
}
}
- 运行截图
2.编写一个程序,将链表中的学生英语成绩单存放到一个树集中,使得按成绩自动排序,并输出排序结果。
- 代码
import java.util.*;
class Student implements Comparable {
//Student类通过实现Comparable接口规定按english确定大小关系
int english = 0;
String name;
Student(int english, String name) {
this.name = name;
this.english = english;
}
public int compareTo(Object b) {
Student st = (Student) b;
return (this.english - st.english);
}
}
public class Shuji {
public static void main(String args[]) {
TreeSet<Student> mytree = new TreeSet<Student>();
//创建树集对象
Student st1, st2, st3, st4;
st1 = new Student(100, "小红");
st2 = new Student(65, "小军");
st3 = new Student(89, "小绿");
st4 = new Student(30, "小明");
mytree.add(st1);
//以上几句代码可以简写为mytree.add(new Student(90,"赵一"));
mytree.add(st2);
mytree.add(st3);
mytree.add(st4);
Iterator<Student> te = mytree.iterator();//创建迭代器
while (te.hasNext()) {
Student stu = te.next();
System.out.println("" + stu.name + " " + stu.english);
//依次输出排序好的结点
}
}
}
- 运行截图
3.有10个U盘,有两个重要的属性:价格和容量。编写一个应用程序,使用TreeMap
- 代码
import java.util.*;
class UDiscKey implements Comparable {
double key=0;
UDiscKey(double d) {
key=d;
}
public int compareTo(Object b) {
UDiscKey disc=(UDiscKey)b;
if((this.key-disc.key)==0)
return -1;
else
return (int)((this.key-disc.key)*1000);
}
}
class UDisc{
int amount;
double price;
UDisc(int m,double e) {
amount=m;
price=e;
}
}
public class G {
public static void main(String args[ ]) {
TreeMap<UDiscKey,UDisc> treemap= new TreeMap<UDiscKey,UDisc>();
int amount[]={1,2,4,8,16,32,64,128,256,512};
double price[]={30,80,867,129,266,908,390,556,455,230};
UDisc UDisc[]=new UDisc[10];
for(int k=0;k<UDisc.length;k++) {
UDisc[k]=new UDisc(amount[k],price[k]);
}
UDiscKey key[]=new UDiscKey[10] ;
for(int k=0;k<key.length;k++) {
key[k]=new UDiscKey(UDisc[k].amount);
}
for(int k=0;k<UDisc.length;k++) {
treemap.put(key[k],UDisc[k]);
}
int number=treemap.size();
Collection<UDisc> collection=treemap.values();
Iterator<UDisc> iter=collection.iterator();
System.out.println("按照容量升序排序后:");
while(iter.hasNext()) {
UDisc disc=iter.next();
System.out.println(""+disc.amount+"G "+disc.price+"元");
}
treemap.clear();
for(int k=0;k<key.length;k++) {
key[k]=new UDiscKey(UDisc[k].price);
}
for(int k=0;k<UDisc.length;k++) {
treemap.put(key[k],UDisc[k]);
}
number=treemap.size();
collection=treemap.values();
iter=collection.iterator();
System.out.println("按照价格升序排列后:");
while(iter.hasNext()) {
UDisc disc=iter.next();
System.out.println(""+disc.amount+"G "+disc.price+"元");
}
}
}
- 运行截图
四、课上内容补做
3.数据结构-单链表
补充MyList.java的内容,提交运行结果截图(全屏)课下推送代码到码云
public class MyList {
public static void main(String [] args) {
//选用合适的构造方法,用你学号前后各两名同学的学号创建四个结点
//把上面四个节点连成一个没有头结点的单链表
//遍历单链表,打印每个结点的
//把你自己插入到合适的位置(学号升序)
//遍历单链表,打印每个结点的
//从链表中删除自己
//遍历单链表,打印每个结点的
}
}
public class Node<T> //单链表结点类,T指定结点的元素类型
{
public T data; //数据域,存储数据元素
public Node<T> next; //地址域,引用后继结点
public Node(T data, Node<T> next) //构造结点,data指定数据元素,next指定后继结点
{
this.data = data; //T对象引用赋值
this.next = next; //Node<T>对象引用赋值
}
public Node()
{
this(null, null);
}
public String toString() //返回结点数据域的描述字符串
{
return this.data.toString();
}
}
补充后代码:
import java.util.*;
public class MyList {
public static void main(String [] args) {
List<String> list=new LinkedList<String>();
list.add("20165310");
list.add("20165311");
list.add("20165313");
list.add("20165314");
System.out.println("打印初始链表");
//把上面四个节点连成一个没有头结点的单链表
Iterator<String> iter=list.iterator();
while(iter.hasNext()){
String te=iter.next();
System.out.println(te);
}
//遍历单链表,打印每个结点的
list.add("20165312");
//把你自己插入到合适的位置(学号升序)
System.out.println("插入我的学号后排序,打印链表");
Collections.sort(list);
iter=list.iterator();
while(iter.hasNext()){
String te=iter.next();
System.out.println(te);
}
//遍历单链表,打印每个结点的
list.remove("20165312");
//从链表中删除自己
System.out.println("删除我的学号后打印链表");
iter=list.iterator();
while(iter.hasNext()){
String te=iter.next();
System.out.println(te);
}
//遍历单链表,打印每个结点的
}
}