分类
Java

Java中ArrayList类的用法

Java中ArrayList类的用法(转)

1、什么是ArrayList
ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处:
动态的增加和减少元素
实现了ICollection和IList接口
灵活的设置数组的大小

2、如何使用ArrayList
最简单的例子:
ArrayList list = new ArrayList();
for( int i=0;i <10;i++ ) //给数组增加10个Int元素
list.add(i);
//..程序做一些处理
list.remove(5);//将第6个元素移除
for( int i=0;i <3;i++ ) //再增加3个元素
list.add(i+20);

3、ArrayList和LinkedList的大致区别:

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

ArrayList和LinkedList是两个集合类,用于存储一系列的对象引用(references)。例如我们可以用ArrayList来存储一系列的String或者Integer。那么ArrayList和LinkedList在性能上有什么差别呢?什么时候应该用ArrayList什么时候又该用LinkedList呢?
一.时间复杂度
首先一点关键的是,ArrayList的内部实现是基于基础的对象数组的,因此,它使用get方法访问列表中的任意一个元素时(random access),它的速度要比LinkedList快。LinkedList中的get方法是按照顺序从列表的一端开始检查,直到另外一端。对LinkedList而言,访问列表中的某个指定元素没有更快的方法了。
假设我们有一个很大的列表,它里面的元素已经排好序了,这个列表可能是ArrayList类型的也可能是LinkedList类型的,现在我们对这个列表来进行二分查找(binary search),比较列表是ArrayList和LinkedList时的查询速度,看下面的程序:

Java代码  收藏代码
  1. package com.mangocity.test;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import java.util.Random;
  5. import java.util.ArrayList;
  6. import java.util.Arrays;
  7. import java.util.Collections;
  8. public class TestList …{
  9.      public static final int N=50000;
  10.      public static List values;
  11.      static…{
  12.          Integer vals[]=new Integer[N];
  13.          Random r=new Random();
  14.          for(int i=0,currval=0;i<N;i++)…{
  15.              vals=new Integer(currval);
  16.              currval+=r.nextInt(100)+1;
  17.          }
  18.          values=Arrays.asList(vals);
  19.      }
  20.      static long timeList(List lst)…{
  21.          long start=System.currentTimeMillis();
  22.          for(int i=0;i<N;i++)…{
  23.              int index=Collections.binarySearch(lst, values.get(i));
  24.              if(index!=i)
  25.                  System.out.println(“***错误***”);
  26.          }
  27.          return System.currentTimeMillis()-start;
  28.      }
  29.      public static void main(String args[])…{
  30.          System.out.println(“ArrayList消耗时间:”+timeList(new ArrayList(values)));
  31.          System.out.println(“LinkedList消耗时间:”+timeList(new LinkedList(values)));
  32.      }
  33. }

我得到的输出是:ArrayList消耗时间:15
LinkedList消耗时间:2596
这个结果不是固定的,但是基本上ArrayList的时间要明显小于LinkedList的时间。因此在这种情况下不宜用LinkedList。二分查找法使用的随机访问(random access)策略,而LinkedList是不支持快速的随机访问的。对一个LinkedList做随机访问所消耗的时间与这个list的大小是成比例的。而相应的,在ArrayList中进行随机访问所消耗的时间是固定的。
这是否表明ArrayList总是比LinkedList性能要好呢?这并不一定,在某些情况下LinkedList的表现要优于ArrayList,有些算法在LinkedList中实现时效率更高。比方说,利用Collections.reverse方法对列表进行反转时,其性能就要好些。
看这样一个例子,加入我们有一个列表,要对其进行大量的插入和删除操作,在这种情况下LinkedList就是一个较好的选择。请看如下一个极端的例子,我们重复的在一个列表的开端插入一个元素:

Java代码  收藏代码
  1. package com.mangocity.test;
  2. import java.util.*;
  3. public class ListDemo {
  4.      static final int N=50000;
  5.      static long timeList(List list){
  6.      long start=System.currentTimeMillis();
  7.      Object o = new Object();
  8.      for(int i=0;i<N;i++)
  9.          list.add(0, o);
  10.      return System.currentTimeMillis()-start;
  11.      }
  12.      public static void main(String[] args) {
  13.          System.out.println(“ArrayList耗时:”+timeList(new ArrayList()));
  14.          System.out.println(“LinkedList耗时:”+timeList(new LinkedList()));
  15.      }
  16. }

这时我的输出结果是:ArrayList耗时:2463
LinkedList耗时:15
这和前面一个例子的结果截然相反,当一个元素被加到ArrayList的最开端时,所有已经存在的元素都会后移,这就意味着数据移动和复制上的开销。相反的,将一个元素加到LinkedList的最开端只是简单的未这个元素分配一个记录,然后调整两个连接。在LinkedList的开端增加一个元素的开销是固定的,而在ArrayList的开端增加一个元素的开销是与ArrayList的大小成比例的。
二.空间复杂度
在LinkedList中有一个私有的内部类,定义如下:

Java代码  收藏代码
  1. private static class Entry {
  2.          Object element;
  3.          Entry next;
  4.          Entry previous;
  5.      }

每个Entry对象reference列表中的一个元素,同时还有在LinkedList中它的上一个元素和下一个元素。一个有1000个元素的LinkedList对象将有1000个链接在一起的Entry对象,每个对象都对应于列表中的一个元素。这样的话,在一个LinkedList结构中将有一个很大的空间开销,因为它要存储这1000个Entity对象的相关信息。
ArrayList使用一个内置的数组来存储元素,这个数组的起始容量是10.当数组需要增长时,新的容量按如下公式获得:新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增长50%。这就意味着,如果你有一个包含大量元素的ArrayList对象,那么最终将有很大的空间会被浪费掉,这个浪费是由ArrayList的工作方式本身造成的。如果没有足够的空间来存放新的元素,数组将不得不被重新进行分配以便能够增加新的元素。对数组进行重新分配,将会导致性能急剧下降。如果我们知道一个ArrayList将会有多少个元素,我们可以通过构造方法来指定容量。我们还可以通过trimToSize方法在ArrayList分配完毕之后去掉浪费掉的空间。
三.总结
ArrayList和LinkedList在性能上各有优缺点,都有各自所适用的地方,总的说来可以描述如下:
1.对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。
2.在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
3.LinkedList不支持高效的随机元素访问。
4.ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。

分类
Java

java数组排序

import java.util.Random;

/**
* 排序测试类
*
* 排序算法的分类如下:
* 1.插入排序(直接插入排序、折半插入排序、希尔排序);
* 2.交换排序(冒泡泡排序、快速排序);
* 3.选择排序(直接选择排序、堆排序);
* 4.归并排序;
* 5.基数排序。
*
* 关于排序方法的选择:
* (1)若n较小(如n≤50),可采用直接插入或直接选择排序。
*  当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。
* (2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;
* (3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
*
* @author WangRuifeng
*/
public class SortTest {

/**
* 初始化测试数组的方法
* @return 一个初始化好的数组
*/
public int[] createArray() {
Random random = new Random();
int[] array = new int[10];
for (int i = 0; i < 10; i++) {
array[i] = random.nextInt(100) – random.nextInt(100);//生成两个随机数相减,保证生成的数中有负数
}
System.out.println(“==========原始序列==========”);
printArray(array);
return array;
}

/**
* 打印数组中的元素到控制台
* @param source
*/
public void printArray(int[] source) {
for (int i : source) {
System.out.print(i + ” “);
}
System.out.println();
}

/**
* 交换数组中指定的两元素的位置
* @param source
* @param x
* @param y
*/
private void swap(int[] source, int x, int y) {
int temp = source[x];
source[x] = source[y];
source[y] = temp;
}

/**
* 冒泡排序—-交换排序的一种
* 方法:相邻两元素进行比较,如有需要则进行交换,每完成一次循环就将最大元素排在最后(如从小到大排序),下一次循环是将其他的数进行类似操作。
* 性能:比较次数O(n^2),n^2/2;交换次数O(n^2),n^2/4
*
* @param source 要排序的数组
* @param sortType 排序类型
* @return
*/
public void bubbleSort(int[] source, String sortType) {
if (sortType.equals(“asc”)) { //正排序,从小排到大
for (int i = source.length – 1; i > 0; i–) {
for (int j = 0; j < i; j++) {
if (source[j] > source[j + 1]) {
swap(source, j, j + 1);
}
}
}
} else if (sortType.equals(“desc”)) { //倒排序,从大排到小
for (int i = source.length – 1; i > 0; i–) {
for (int j = 0; j < i; j++) {
if (source[j] < source[j + 1]) {
swap(source, j, j + 1);
}
}
}
} else {
System.out.println(“您输入的排序类型错误!”);
}
printArray(source);//输出冒泡排序后的数组值
}

/**
* 直接选择排序法—-选择排序的一种
* 方法:每一趟从待排序的数据元素中选出最小(或最大)的一个元素, 顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
* 性能:比较次数O(n^2),n^2/2
* 交换次数O(n),n
* 交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CUP时间多,所以选择排序比冒泡排序快。
* 但是N比较大时,比较所需的CPU时间占主要地位,所以这时的性能和冒泡排序差不太多,但毫无疑问肯定要快些。
*
* @param source 要排序的数组
* @param sortType 排序类型
* @return
*/
public void selectSort(int[] source, String sortType) {

if (sortType.equals(“asc”)) { //正排序,从小排到大
for (int i = 0; i < source.length; i++) {
for (int j = i + 1; j < source.length; j++) {
if (source[i] > source[j]) {
swap(source, i, j);
}
}
}
} else if (sortType.equals(“desc”)) { //倒排序,从大排到小
for (int i = 0; i < source.length; i++) {
for (int j = i + 1; j < source.length; j++) {
if (source[i] < source[j]) {
swap(source, i, j);
}
}
}
} else {
System.out.println(“您输入的排序类型错误!”);
}
printArray(source);//输出直接选择排序后的数组值
}

/**
* 插入排序
* 方法:将一个记录插入到已排好序的有序表(有可能是空表)中,从而得到一个新的记录数增1的有序表。
* 性能:比较次数O(n^2),n^2/4
* 复制次数O(n),n^2/4
* 比较次数是前两者的一般,而复制所需的CPU时间较交换少,所以性能上比冒泡排序提高一倍多,而比选择排序也要快。
*
* @param source 要排序的数组
* @param sortType 排序类型
*/
public void insertSort(int[] source, String sortType) {
if (sortType.equals(“asc”)) { //正排序,从小排到大
for (int i = 1; i < source.length; i++) {
for (int j = i; (j > 0) && (source[j] < source[j – 1]); j–) {
swap(source, j, j – 1);
}
}
} else if (sortType.equals(“desc”)) { //倒排序,从大排到小
for (int i = 1; i < source.length; i++) {
for (int j = i; (j > 0) && (source[j] > source[j – 1]); j–) {
swap(source, j, j – 1);
}
}
} else {
System.out.println(“您输入的排序类型错误!”);
}
printArray(source);//输出插入排序后的数组值
}

/**
* 反转数组的方法
* @param source 源数组
*/
public void reverse(int[] source) {

int length = source.length;
int temp = 0;//临时变量

for (int i = 0; i < length / 2; i++) {
temp = source[i];
source[i] = source[length – 1 – i];
source[length – 1 – i] = temp;
}
printArray(source);//输出到转后数组的值
}

/**
* 快速排序
* 快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
* 步骤为:
* 1. 从数列中挑出一个元素,称为 “基准”(pivot),
* 2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割之后,该基准是它的最后位置。这个称为分割(partition)操作。
* 3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
* 递回的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递回下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
* @param source 待排序的数组
* @param low
* @param high
* @see SortTest#qsort(int[], int, int)
* @see SortTest#qsort_desc(int[], int, int)
*/
public void quickSort(int[] source, String sortType) {
if (sortType.equals(“asc”)) { //正排序,从小排到大
qsort_asc(source, 0, source.length – 1);
} else if (sortType.equals(“desc”)) { //倒排序,从大排到小
qsort_desc(source, 0, source.length – 1);
} else {
System.out.println(“您输入的排序类型错误!”);
}
}

/**
* 快速排序的具体实现,排正序
* @param source
* @param low
* @param high
*/
private void qsort_asc(int source[], int low, int high) {
int i, j, x;
if (low < high) { //这个条件用来结束递归
i = low;
j = high;
x = source[i];
while (i < j) {
while (i < j && source[j] > x) {
j–; //从右向左找第一个小于x的数
}
if (i < j) {
source[i] = source[j];
i++;
}
while (i < j && source[i] < x) {
i++; //从左向右找第一个大于x的数
}
if (i < j) {
source[j] = source[i];
j–;
}
}
source[i] = x;
qsort_asc(source, low, i – 1);
qsort_asc(source, i + 1, high);
}
}

/**
* 快速排序的具体实现,排倒序
* @param source
* @param low
* @param high
*/
private void qsort_desc(int source[], int low, int high) {
int i, j, x;
if (low < high) { //这个条件用来结束递归
i = low;
j = high;
x = source[i];
while (i < j) {
while (i < j && source[j] < x) {
j–; //从右向左找第一个小于x的数
}
if (i < j) {
source[i] = source[j];
i++;
}
while (i < j && source[i] > x) {
i++; //从左向右找第一个大于x的数
}
if (i < j) {
source[j] = source[i];
j–;
}
}
source[i] = x;
qsort_desc(source, low, i – 1);
qsort_desc(source, i + 1, high);
}
}

/**
* 二分法查找
* 查找线性表必须是有序列表
*
* @param source
* @param key
* @return
*/
public int binarySearch(int[] source, int key) {
int low = 0, high = source.length – 1, mid;
while (low <= high) {
mid = (low + high) >>> 1; //相当于mid = (low + high) / 2,但是效率会高些
if (key == source[mid]) {
return mid;
} else if (key < source[mid]) {
high = mid – 1;
} else {
low = mid + 1;
}
}
return -1;
}

public static void main(String[] args) {
SortTest sortTest = new SortTest();

int[] array = sortTest.createArray();

System.out.println(“==========冒泡排序后(正序)==========”);
sortTest.bubbleSort(array, “asc”);
System.out.println(“==========冒泡排序后(倒序)==========”);
sortTest.bubbleSort(array, “desc”);

array = sortTest.createArray();

System.out.println(“==========倒转数组后==========”);
sortTest.reverse(array);

array = sortTest.createArray();

System.out.println(“==========选择排序后(正序)==========”);
sortTest.selectSort(array, “asc”);
System.out.println(“==========选择排序后(倒序)==========”);
sortTest.selectSort(array, “desc”);

array = sortTest.createArray();

System.out.println(“==========插入排序后(正序)==========”);
sortTest.insertSort(array, “asc”);
System.out.println(“==========插入排序后(倒序)==========”);
sortTest.insertSort(array, “desc”);

array = sortTest.createArray();
System.out.println(“==========快速排序后(正序)==========”);
sortTest.quickSort(array, “asc”);
sortTest.printArray(array);
System.out.println(“==========快速排序后(倒序)==========”);
sortTest.quickSort(array, “desc”);
sortTest.printArray(array);

System.out.println(“==========数组二分查找==========”);
System.out.println(“您要找的数在第” + sortTest.binarySearch(array, 74) + “个位子。(下标从0计算)”);
}
}

字符串排序:

public class StringSort {
public static void main(String []args) {
String[] s={“a”,”b”,”c”,”d”,”m”,”f”};
for(int i=s.length-1;i>=1;i–){
for(int j=0;j<=i-1;j++) {
if(s[j].compareTo(s[j+1])<0) {
String temp=null;
temp=s[j];
s[j]=s[j+1];
s[j+1]=temp;
}
}
}
for(String a:s){
System.out.print(a+” “);
}
}
}
比较字符串的实质是比较字符串的字母,首字母相同,比较下一个,然后又相同的话,再下一个….所以你可以先用substring();截出第一个字符,然后再比较,相同的再截第二个,…..

分类
Java

java 数组

数组是编程语言中最常见的一种数据结构,可以用于存储多个数据,每个数组元素存放一个数据,通常可以通过数组元素的索引来访问数组元素,包括为数组元素赋值和取出数组元素的值。java语言的数组具有特有的特征

数组也是一种类型
    java数组要求所有的数组元素具有相同的数据类型。因此,在一个数组中,数组元素的类型是唯一的,即一个数组里只能存储一种数据类型的数据,而不能存储多种数据类型的数据。
    一旦数组的初始化完成,数组在内存中所占的空间就被固定下来,因此数组的长度将不可改变。即使把某个数组元素清空,但它所占用的空间依然保留,依然属于该数组,数组的长度依然不变。
    java的数组既可以存储基本类型的数据,也可以存储引用类型的数据,只有所有的数组元素具有相同的类型即可。
    值得提出的是,数组也是一种数据类型,它本身是一种引用类型。

http://jingyan.baidu.com/article/148a19217886834d71c3b1c1.html

数组是有序数据的集合,数组中的每个元素具有相同的数组名和下标来唯一地确定数组中的元素。

§5.1一维数组

一、一维数组的定义

type arrayName[];

其中类型(type)可以为Java中任意的数据类型,包括简单类型组合类型,数组名arrayName为一个合法的标识符,[]指明该变量是一个数组类型变量。例如:

int intArray[];

声明了一个整型数组,数组中的每个元素为整型数据。与C、C++不同,Java在数组的定义中并不为数组元素分配内存,因此[]中不用指出数组中元素个数,即数组长度,而且对于如上定义的一个数组是不能访问它的任何元素的。我们必须为它分配内存空间,这时要用到运算符new,其格式如下:

arrayName=new type[arraySize];

其中,arraySize指明数组的长度。如:

intArray=new int[3];

为一个整型数组分配3个int型整数所占据的内存空间。

通常,这两部分可以合在一起,格式如下:

type arrayName=new type[arraySize]; 

例如:

int intArray=new int[3];

二、一维数组元素的引用

定义了一个数组,并用运算符new为它分配了内存空间后,就可以引用数组中的每一个元素了。数组元素的引用方式为:

arrayName[index]

其中:index为数组下标,它可以为整型常数或表达式。如a[3],b[i](i为整型),c[6*I]等。下标 从0开始,一直到数组的长度减1。对于上面例子中的in-tArray数来说,它有3个元素,分别为: 

intArray[0],intArray[1],intArray[2]。注意:没有intArray[3]。

另外,与C、C++中不同,Java对数组元素要进行越界检查以保证安全性。同时,对于每个数组都有一个属性length指明它的长度,例如:intArray.length指明数组intArray的长度。

例5.1

public class ArrayTest{
public static void main(String args[]){
int i;
int a[]=newint[5];
for(i=0;i<5;i++)
a[i]=i;
for(i=a.length-1;i>=0;i--)
System.out.println("a["+i+"]="+a[i]);
}
}

运行结果如下:

C:\>java ArrayTest

a[4]=4
a[3]=3
a[2]=2
a[1]=1
a[0]=0

该程序对数组中的每个元素赋值,然后按逆序输出。

三、一维数组的初始化

对数组元素可以按照上述的例子进行赋值。也可以在定义数组的同时进行初始化。

例如:

int a[]={1,2,3,4,5};

用逗号(,)分隔数组的各个元素,系统自动为数组分配一定空间。

与C中不同,这时Java不要求数组为静态(static)。

四、一维数组程序举例:

例5.2Fibonacci数列

Fibonacci数列的定义为:

F1=F2=1,Fn=Fn-1+Fn-2(n>=3)

public classFibonacci{
public static void main(String args[]){
int i;
int f[]=new int[10];
f[0]=f[1]=1;
for(i=2;i<10;i++)
f[i]=f[i-1]+f[i-2];
for(i=1;i<=10;i++)
System.out.println("F["+i+"]="+f[i-1]);
}
}

运行结果为:

C:\>java Fibonacci

F[1]=1
F[2]=1
F[3]=2
F[4]=3
F[5]=5
F[6]=8
F[7]=13
F[8]=21
F[9]=34
F[10]=55

例5.3冒泡法排序(从小到大)

冒泡法排序对相邻的两个元素进行比较,并把小的元素交到前面。

public class BubbleSort{
public static void main(String args[]){
int i,j;
int intArray[]={30,1,-9,70,25};
int l=intArray.length;
for(i=0;i<l-1;i++)
for(j=i+1;j<l;j++)
if(intArray[i]>intArray[j]){
int t=intArray[i];
intArray[i]=intArray[j];
intArray[j]=t;
}
for(i=0;i<l;i++)
System.out.println(intArray[i]+"");
}
}

运行结果为:

C:\>java BubbleSort
-9
1
25
30
70

§5.2多维数组

与C、C++一样,Java中多维数组被看作数组的数组。例如二维数组为一个特殊的一维数组,其每个元素又是一个一维数组。下面我们主要以二维数为例来进行说明,高维的情况是类似的。

一、二维数组的定义

二维数组的定义方式为:

type arrayName[][];

例如:

int intArray[][];

与一维数组一样,这时对数组元素也没有分配内存空间,同要使用运算符new来分配内存,然后才可以访问每个元素。

对高维数组来说,分配内存空间有下面几种方法:

1直接为每一维分配空间,如:

int a[][]=new int[2][3];

2从最高维开始,分别为每一维分配空间,如:

int a[][]=new int[2][];
a[0]=new int[3];
a[1]=new int[3];

完成1中相同的功能。这一点与C、C++是不同的,在C、C++中必须一次指明每一维的长度。

二、二维数组元素的引用

对二维数组中每个元素,引用方式为:arrayName[index1][index2] 其中index1、index2为下标,可为整型常数或表达式,如a[2][3]等,同样,每一维的下标都从0开始。

三、二维数组的初始化

有两种方式:

1直接对每个元素进行赋值。

2在定义数组的同时进行初始化。

如:int a[][]={{2,3},{1,5},{3,4}};

定义了一个3×2的数组,并对每个元素赋值。

四、二维数组举例:

例5.4矩阵相乘

两个矩阵Am×n、Bn×l相乘得到Cm×l,每个元素Cij=?aik*bk (i=1..m,n=1..n)

public class MatrixMultiply{
public static void main(String args[]){
int i,j,k;
int a[][]=new int[2][3];
int b[][]={{1,5,2,8},{5,9,10,-3},{2,7,-5,-18}};
int c[][]=new int[2][4];
for(i=0;i<2;i++)
for(j=0;j<3;j++)
a[i][j]=(i+1)*(j+2);
for(i=0;i<2;i++){
for(j=0;j<4;j++){
c[i][j]=0;
for(k=0;k<3;k++)
c[i][j]+=a[i][k]*b[k][j];
}
}
System.out.println("\n***MatrixA***");
for(i=0;i<2;i++){
for(j=0;j<3;j++)
System.out.print(a[i][j]+"");
System.out.println();
}
System.out.println("\n***MatrixB***");
for(i=0;i<3;i++){
for(j=0;j<4;j++)
System.out.print(b[i][j]+"");
System.out.println();
}
System.out.println("\n***MatrixC***");
for(i=0;i<2;i++){
for(j=0;j<4;j++)
System.out.print(c[i][j]+"");
System.out.println();
}
}
}

其结果为:

C:\>java MatrixMultiply

for(j=0;j<4;j++)
System.out.print(c[i][j]+"");
System.out.println();
}
}
}

其结果为:

C:\>java MatrixMultiply

***MatrixA***
2 3 4
4 6 8
***MatrixB***
1 5 2 8
5 9 10 -3
2 7 -5 -18
***MatrixC***
25 65 14 -65
50 130 28 -130

如果你学过线性代数,应该可以比较好地理解多维数组。
多维数组和矩阵结合紧密。

a[i][j]就是第i-1行的第j-1列的元素,因为下标是从0开始的。
比如:
一个数组:1  2  3
          4  5  6
a[0][0]=1 a[0][1]=2 a[0][2]=3
a[1][0]=3 a[1][1]=5 a[1][2]=6
分类
Java

Java中的字符串类String、StringBuffer、StringBuilder

首先String、StringBuffer、StringBuilder都是java中的字符串类它们的具体区别如下:

String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象,因为在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

这里尝试一个例子: String S1 = “abc”; For(int I = 0 ; I < 10000 ; I ++) // 程序的多次调用 { S1 + = “accp”; S1 = “北大青鸟”; } 如果是这样的话,到这个 for 循环完毕后,如果内存中的对象没有被 GC 清理掉的话,内存中一共有 2 万多个了对象,惊人的数目,而如果这是一个很多人使用的系统,这样的数目就会可想而知了,所以大家使用的时候一定要小心。

而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。

而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的: String S1 = “This is only a” + “ simple” + “ test”; StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”); 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。因为,S1被设定的值被Jvm认为是一个字符串,所以速度也比StringBuffer调用方法快。

如果你的字符串是来自另外的 String 对象的话,速度就没那么快了。比如: String S2 = “this is a ”; String S3 = “ shool”; String S4 = “ of chinese”; String S1 = S2 +S3 + S4;

再看StringBuilder 和StringBuffer 的区别: StringBuilder 是 JDK5.0 中新增加的一个类,它跟 StringBuffer 的区别 Java.lang.StringBuffer 线程安全的可变字符序列。类似于 String 的字符串缓冲区,但不能修改。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发 生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。 每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量 自动增大。从 JDK 5.0 开始,为该类增添了一个单个线程使用的等价类,即 StringBuilder 。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。 但是如果将 StringBuilder 的实例用于多个线程是不安全的。需要这样的同步,则建议使用 StringBuffer 。

总结:
String 的所有操作都要生成新的对象.
StringBuffer 的所有操作, 对象不变.
StringBuilder 是StringBuffer等价类, 但线程不安全.
String 的一次性连加操作等效于 StringBuffer

分类
Java

String类

String类型是引用类型,然而这个引用类型比较特殊,它指向一个字符串,这个字符串的值不能够改变。

 以下是String类的常用方法: 

     1public String(char [] value):将字符数组转成字符串; 

     例:char c[]={“f”, “w”, “s”,“w”,“g”,“a”};

            String s=new String(c);

            System.out.println(s);            

            结果为:fwswga 

      2public String(cahr [] value,开始位置,新字符串的长度):将指定位置长度的字符数组转成字符串;       

     例:char c[]={“f”, “w”, “s”, “w”, “g”, “a” }      

            String s=new String(c,2,2);      

            System.out.println(c);        

            结果为:sw 

      3public String (byte [ ] value):将字节数组转成字符串;      

      例:byte b[]={“w”, “o”, “r”, “l”, “d”, “!”};      

             String s=new String(b);     

             System.out.println(s);              

             结果为:world! 

       4 public String (byte [] value,开始位置,新字符串长度);将指定位置长度的字节数组转成字符串; 

       例:byte b[]={“w”, “o”, “r”, “l”, “d”, “!”};

              String s=new String(b,2,3);

              System.out.println(s);   

              结果为:rl  

       5public char[] toCharArray();将字符数组转成字符串   

       例:String s=“Hello”;    

             Char c[]=s.toCharArray();   

             for (int i=0;i<c.length;i++) {  

             System.out.print(c[i]+ “\t”);

             }     

             结果为:  H e l l o 

       6public char charAt(int index字符下标):返回字符串中指定位置的字符  

       例:String s=“Hello”;   

              System.out.println(s.charAt(3));    

              结果为:

       7public byte() getBytes():将一个字符串转成字节数组,默认输出值为ASCII码值   

      例:String s=“Hello”; 

             byte b[]=s.getBytes();

             for (int i=0;i<b.length;i++) {   

             System.out.print((char)b[i]+ “\t”);

             }  

             结果为:H e l l o

       8public int length():求字符串的长度 

      例:String s=“dwfsdfwfsadf”;

             System.out.pritnln(s.length());  

             结果为:12  

      9public int indexOf(String str):从头查找指定的字符串的位置,返回值为整型,从0开始,如果没找到,则返回-1      

      例:String s=“sdfwefsdgwe”;      

             System.out.println(s.indexOf(“e”));           

             结果为:

      10public int indexOf(String str,指定位置);从指定位置开始查找指定的字符串     

       例:String s=“dfwfgasdfwf”;      

              System.out.println(s.indexOf(“a”,8));       

              结果为:-1 

      11public String trim():清除字符串左右两端的空格     

      例:String s=“   sdfsdfs   ”;     

             System.out.println(s.trim);       

             结果为:sdfsdfs 

      12public String substring(int beginindex):从指定位置到结尾截取字符串    

      例:String s=“fjeiflsjfowjflsdfjo”;   

             System.out.println(s.substring(5));       

             结果为:lsjfowjflsdfjo 

      13public String substring(int begin,int end);指定截取字符串的开始和结束位置,不包含结束字符        

      例:String s=“foweflsdfjowefjls”;        

             System.out.println(s.substring(4,9));               

             结果为:flsdf 

      14public String [] split(String str);按指定的字符分割字符串       

      例:String s=“fwefsdfefgefaselieffs”;       

             String ss[]=s.split(“e”);       

             for (int i=0;i<ss.length;i++) {            

                   System.out.print(ss[i]+ “\t”);       

             }        

             System.out.println();              

             结果为:fw  fsdf   fg    fas  li  ffs 

      15public  String  toUpperCase():将字符串全部转换成大写      

      例:System.out.println(new String(“hello”).toUpperCase());              

             结果为:HELLO 

      16public String toLowerCase();将字符全部转成小写       

      例:System.out.println(new String(“HELLO”).toLowerCase());        

             结果为:hello 

      17public boolean startsWith(String str);判断字符串是否由指定的字符串开头      

      例:String s=“fwofsdfjwkfs”;       

             System.out.println(s.startsWith(“fw”));      

             System.out.println(s.startsWith(“wf”));      

             结果为:true              

                           false 

      18public boolean endsWith(String str):判断字符串是否由指定的字符串结尾      

      例:String s=“fwefsdgjgrg”;       

             System.out.println(s.endsWith(“fe”));      

             System.out.println(s.endsWith(“rg”));      

             结果为:false

                            true 

      19public boolean equals(String str):判断两个字符串是否相等,区分大小写     

      例:String s1=“hello”;      

             String s2=new String(“hello”);     

             String s3=“Hello”;      

             System.out.println(s1.equals(s2));     

             System.out.println(s1.equals(s3));     

             结果为:true

                            false 

      20public boolean equalsIgnoreCase(String str):不区分大小写判断俩个字符串是否相等 

       例:String s1=“hello”;

              String s2=“HEllo”; 

              System.out.println(s1.equalsIgnoreCase(s2));

              结果为:true 

      21public String replaceAll(String str1String str2);将字符串中str1替换成str2 

      例:String s=“geowfjsklgoasdf”; 

             System.out.println(s.replaceAll(“f”, “s”));

             结果为:geowsjsklgoasds

分类
Java

java 循环

Java中循环有三种形式 while循环、do-while循环 和 for循环。其中从Java 6 开始for循环又分 普通for循环 和 for-each循环两种,我们接下来分别讲解。

   一、while 循环

当条件为真时执行while循环,一直到条件为假时再退出循环体,如果第一次条件表达式就是假,那么while循环将被忽略,如果条件表达式一直为真,那么while循环将一直执行。关于while 括号后的表达式,要求和if语句一样需要返回一个布尔值,用作判断是否进入循环的条件。

java代码:

  1. public class demo3 {
  2. public static void main(String[] args) {
  3. int x = 8;
  4. while (x > 0) {
  5. System.out.println(x);
  6. x–;
  7. }
  8. }
  9. }


如果你把 x>0 改成大于8 ,while循环将一次都不执行

        二、do-while 循环
        好,如果你无论如何都想执行一次循环体内的代码,可以选择do-while循环,它的特点是做了再说。

java代码:

  1. public class demo4 {
  2. public static void main(String[] args) {
  3. int x = 8;
  4. do{
  5. System.out.println(x);
  6. x–;
  7. }while(x>8);
  8. }
  9. }


x=8,条件是大于8,查看运行结果,我们发现他总是会执行一次。

       三、for 循环
当知道可以循环多少次时,是使用for循环的最佳时机。
       1、基本for循环:

2.jpg

 

看看实例吧:

java代码:

 

 

  1. public class demo5 {
  2. public static void main(String[] args) {
  3. for (int i = 2, j = 1; j < 10; j++) {
  4. if (j >= i) {
  5. System.out.println(i + “x” + j + “=” + i * j);
  6. }
  7. }
  8. }
  9. }


下面说一下for循环的规则:

        1)、for循环的三个部分任意部分都可以省略,最简单的for循环就是这样的 for(;;){ }
        2)、中间的条件表达式必须返回一个布尔值,用来作为是否进行循环的判断依据
        3)、初始化语句可以由初始化多个变量,多个变量之间可以用逗号隔开,这些在for循环中声明的变量作用范围就只在for循环内部
       4)、最后的迭代语句可以是 i++,j++ 这样的表达式,也可以是毫无干系的 System.out.println(“哈哈”) 之类的语句,它照样在循环体执行完毕之后被执行。

       2、for-each循环:

for-each循环又叫增强型for循环,它用来遍历数组和集合中的元素,。

这里举个例子给你看看先:

java代码:

  1. public class demo6 {
  2. public static void main(String[] args) {
  3. int[] a = { 6, 2, 3, 8 };
  4. for (int n : a) {
  5. System.out.println(n);
  6. }
  7. }
  8. }

复制代码

       四、跳出循环 break 、continue

break关键字用来终止循环或switch语句,continue关键字用来终止循环的当前迭代。当存在多层循环时,不带标签的break和continue只能终止离它所在的最内层循环,如果需要终止它所在的较外层的循环则必须用,标签标注外层的循环,并使用break和continue带标签的形式予以明确标示。

先看一个不带标签的例子BreakAndContinue.java:

java代码:

  1. public class BreakAndContinue {
  2. public static void main(String[] args) {
  3. int i =0;
  4. while(true){
  5. System.out.println(“i=”+i);
  6. if(i==12){
  7. i++;
  8. i++;
  9. continue;
  10. }
  11. i++;
  12. if(i==20){
  13. break;
  14. }
  15. }
  16. }
  17. }


好例子自己会说话,这个例子打印了从1到20中除去13的数字。我们只需要看明白这个例子的输出结果就能明白break和continue的区别了。

编译并运行代码,查看结果:

效果图:

3.png

java代码:

  1. public class BreakAndContinue {
  2. public static void main(String[] args) {
  3. boolean isTrue = true;
  4. outer:
  5. for(int i=0;i<5;i++){
  6. while(isTrue){
  7. System.out.println(“Hello”);
  8. break outer;
  9. }
  10. System.out.println(“Outer loop.”);
  11. }
  12. System.out.println(“Good Bye!”);
  13. }
  14. }


分类
Java

for 循环

for循环是一个功能强大且形式灵活的结构。下面是for 循环的通用格式:

for(initialization; condition; iteration) {
// body
}

如只有一条语句需要重复,大括号就没有必要。

for循环的执行过程如下。第一步,当循环启动时,先执行其初始化部分。通常,这是设置循环控制变量值的一个表达式,作为控制循环的计数器。重要的是你要理解初始化表达式仅被执行一次。下一步,计算条件condition 的值。条件condition 必须是布尔表达式。它通常将循环控制变量与目标值相比较。如果这个表达式为真,则执行循环体;如果为假,则循环终止。再下一步执行循环体的反复部分。这部分通常是增加或减少循环控制变量的一个表达式。接下来重复循环,首先计算条件表达式的值,然后执行循环体,接着执行反复表达式。这个过程不断重复直到控制表达式变为假。

下面是使用for 循环的“tick”程序:

// Demonstrate the for loop.
class ForTick {
public static void main(String args[]) {
int n;

for(n=10; n>0; n–)
System.out.println(“tick ” + n);
}
}

 

说明如下:
(1)for循环执行时,首先执行初始化操作,然后判断终止条件是否满足,如果满足,则执行循环体中的语句,最后执行迭代部分。完成一次循环后,重新判断终止条件。
(2)可以在for循环的初始化部分声明一个变量,它的作用域为整个for循环。
(3)for循环通常用于循环次数确定的情况,但也可以根据循环结束条件完成循环次数不确定的情况。
(4)在初始化部分和迭代部分可以使用逗号语句来进行多个操作。逗号语句是用逗号分隔的语句序列。例如:
for(i=0,j=10;i<j;i++.j–}
{

}
(5)初始化、终止以及迭代部分都可以为空语句(但分号不能省),三者均为空的时候,相当于一个无限循环。例如:
for(;;)
{

}
(6) for循环与while循环是可以相互转换的。更确切地说,for循环等同于一个while循环。
例如:
for(i =0,j=10;i<j;i++,j–)
{

}
完全等同于:
i=0;
j=10;
while(i<j)
{

i++;
j–;
}

分类
Java

do-while 循环

如果while 循环一开始条件表达式就是假的,那么循环体就根本不被执行。然而,有时需要在开始时条件表达式即使是假的情况下,while 循环至少也要执行一次。换句话说,有时你需要在一次循环结束后再测试中止表达式,而不是在循环开始时。幸运的是,Java 就提供了这样的循环:do-while 循环。do-while 循环总是执行它的循环体至少一次,因为它的条件表达式在循环的结尾。它的通用格式如下:

do {
// body of loop
} while (condition);

do-while 循环总是先执行循环体,然后再计算条件表达式。如果表达式为真,则循环继续。否则,循环结束。对所有的Java 循环都一样,条件condition 必须是一个布尔表达式。下面是一个重写的“tick”程序,用来演示do-while 循环。它的输出与先前程序的输出相同。

// Demonstrate the do-while loop.
class DoWhile {
public static void main(String args[]) {
int n = 10;

do {
System.out.println(“tick ” + n);
n–;

} while(n > 0);
}
}

该程序中的循环虽然在技术上是正确的,但可以像如下这样编写更为高效:

do {
System.out.println(“tick ” + n);
} while(–n > 0);

在本例中,表达式“– n > 0 ”将n值的递减与测试n是否为0组合在一个表达式中。它的执行过程是这样的。首先,执行– n 语句,将变量n递减,然后返回n的新值。这个值再与0比较,如果比0大,则循环继续。否则结束。

do-while 循环在你编制菜单选择时尤为有用,因为通常都想让菜单循环体至少执行一次。下面的程序是一个实现Java 选择和重复语句的很简单的帮助系统:

// Using a do-while to process a menu selection
class Menu {

public static void main(String args[])
throws java.io.IOException {
char choice;

do {
System.out.println(“Help on:”);
System.out.println(” 1. if”);
System.out.println(” 2. switch”);
System.out.println(” 3. while”);
System.out.println(” 4. do-while”);
System.out.println(” 5. for “);
System.out.println(“Choose one:”);
choice = (char) System.in.read();

} while( choice < ‘1’ || choice > ‘5’);

System.out.println(” “);

switch(choice) {

case ‘1’:
System.out.println(“The if: “);
System.out.println(“if(condition) statement;”);
System.out.println(“else statement;”);

break;

case ‘2’:
System.out.println(“The switch: “);
System.out.println(“switch(expression) {“);
System.out.println(” case constant:”);
System.out.println(” statement sequence”);
System.out.println(” break;”);
System.out.println(” // …”);
System.out.println(“}”);
break;

case ‘3’:
System.out.println(“The while: “);
System.out.println(“while(condition) statement;”);
break;

case ‘4’:
System.out.println(“The do-while: “);
System.out.println(“do {“);

System.out.println(” statement;”);
System.out.println(“} while (condition);”);
break;

case ‘5’:
System.out.println(“The for: “);
System.out.print(“for(init; condition; iteration)”);
System.out.println(” statement;”);
break;

}
}
}

下面是这个程序执行的一个样本输出:

Help on:

1. if
2. switch
3. while
4. do-while
5. for
Choose one:
4
The do-while:
do {

statement;
} while (condition);

在程序中,do-while 循环用来验证用户是否输入了有效的选择。如果没有,则要求用户重新输入。因为菜单至少要显示一次,do-while 循环是完成此任务的合适语句。

关于此例的其他几点:注意从键盘输入字符通过调用System.in.read( ) 来读入。这是一个Java 的控制台输入函数。尽管Java 的终端 I/O (输入/输出)方法将在第12章中详细讨论,在这里使用System.in.read ( ) 来读入用户的选择。它从标准的输入读取字符(返回整数,因此将返回值choice 定义为字符型)。默认地,标准输入是按行进入缓冲区的,因此在你输入的任何字符被送到你的程序以前,必须按回车键。

Java 的终端输入功能相当有限且不好使用。进一步说,大多数现实的Java 程序和applets (小应用程序)都具有图形界面并且是基于窗口的。因此,这本书使用终端的输入并不多。然而,它在本例中是有用的。另外一点:因为使用System.in.read ( ) ,程序必须指定throws java.io.IOException 子句。这行代码对于处理输入错误是必要的。这是Java 的异常处理的一部分。

分类
Java

while 循环

while 语句是Java 最基本的循环语句。当它的控制表达式是真时,while 语句重复执行一个语句或语句块。它的通用格式如下:

 

while(condition) {
// body of loop
}

条件condition 可以是任何布尔表达式。只要条件表达式为真,循环体就被执行。当条件condition 为假时,程序控制就传递到循环后面紧跟的语句行。如果只有单个语句需要重复,大括号是不必要的。

下面的while 循环从10开始进行减计数,打印出10行“tick”。

// Demonstrate the while loop.
class While {
public static void main(String args[]) {
int n = 10;

while(n > 0) {
System.out.println(“tick ” + n);
n–;

}
}
}

当你运行这个程序,它将“tick”10次:

tick 10
tick 9
tick 8
tick 7
tick 6
tick 5
tick 4
tick 3
tick 2
tick 1

因为while 语句在循环一开始就计算条件表达式,若开始时条件为假,则循环体一次也不会执行。例如,下面的程序中,对println( ) 的调用从未被执行过:

int a = 10, b = 20;

while(a > b)
System.out.println(“This will not be displayed”);

while 循环(或Java 的其他任何循环)的循环体可以为空。这是因为一个空语句(null statement) (仅由一个分号组成的语句)在Java 的语法上是合法的。例如,下面的程序:

// The target of a loop can be empty.
class NoBody {
public static void main(String args[]) {

int i, j;

i = 100;
j = 200;

// find midpoint between i and j
while(++i < –j) ; // no body in this loop

System.out.println(“Midpoint is ” + i);
}
}

该程序找出变量i和变量j的中间点。它产生的输出如下:

Midpoint is 150

该程序中的while 循环是这样执行的。值i自增,而值j自减,然后比较这两个值。如果新的值i仍比新的值j小,则进行循环。如果i等于或大于j,则循环停止。在退出循环前,i 将保存原始i和j的中间值(当然,这个程序只有在开始时i比j小的情况下才执行)。正如你看到的,这里不需要循环体。所有的行为都出现在条件表达式自身内部。在专业化的Java 代码中,一些可以由控制表达式本身处理的短循环通常都没有循环体。

 

分类
Java

switch选择语句

在多重条件选择的情况下,可以使用if ...else ...结构来实现其功能,但是,使用多分支开关语句会 使程序更为精练、清晰。switch语句就是多分支的开关语句,常用于多重条件选择。它将一个表达式的值同许多其 他值比较,并按比较结果选择下面执行哪些语句。switch 选择语句的格式如下:

switch多分支选择语句在执行时,首先计算圆括号中“表达式”的值,这个值必须是整型或字符型的量,同时 应与各个case后面的常量表达式值的类型相一致。计算出表达式的值后,将它先与第一个case后面的“常量表达式 1”的值相比较,若相同,则程序的流程转入第一个case分支的语句序列;否则,再将表达式的值与第二个case后面 的“常量表达式2”相比较,依此类推;如果表达式的值与任何一个case后的常量表达式值都不相同,则转去执行最 后的default分支的语句序列。在每个case语句后要用break退出switch结构,最后匹配的条件语句后的break可以省 略。其中,break是流程跳转语句,它的其他用法将在后面介绍。

说明:switch语句的每一个case判断,在一般情况下都有break语句,以指明这个分支执行完后,就跳出该 switch语句。在某些特定的场合下可能不需要break语句,如要若干判断值共享一个分支时,就可以实现由不同的判 断语句流入相同的分支。

【例4.3】利用switch语句来判断给定表达式中的运算符,再输出计算后的结果。

该程序的第6行是将两个整型量分别存入变量a和b中,第9行是从键盘输入一个字符,并将其存放到字符型变量 oper中,然后执行switch 语句,将输入的字符“oper”与每个case后的字符型常量相比较,如果是+、-、*、/四个 符号之一,则执行相应的case分支下的语句,输出相应的计算结果,然后退出switch语句;若输入的不是上述四个 符号之一,则执行default:分支下的语句,输出“输入的符号不正确!”内容后结束程序的执行。