1.1節的內容主要爲介紹Java的基本語法以及書中會用到的庫。java
下圖爲一個Java程序示例和相應的註解:算法
int
爲32位,double
爲64位int
和double
之外的其餘初始數據類型:
++i
等價於i = i + 1
和i += 1
,即先+1,再進行運算;而i++
是先運算再+1。下面演示一下:public class i_test { public static void main(String[] args) { int i = 0; int j = 0; System.out.printf("%s: %d%n","++i",++i); System.out.printf("%s: %d%n","i++",j++); } } /**輸出: ++i: 1 i++: 0 */
double[] a; a = new double[N]; for (int i = 0; i < N; i++) a[i] = 0.0
double[] a = new double[N]; int[] a = {1,1,2,3,6}
double[][] a = new double[M][N];
數組名錶示的是整個數組,若是將一個數組變量賦給另一個變量,則兩個變量將會指向同一個數組:編程
int[] a = new int[N]; a[i] = 1234; int[] b = a; b[i] = 5678 // a[i]也變成5678, 不改變原數組的複製方法見下文
1)找最大值數組
double max = a[0]; for (int i = 1;i < a.length; i++) if (a[i] > max) max = a[i];
2)計算平均值數據結構
int N = a.length; double sum = 0.0; for (int i = 0; i < N; i++) sum += a[i]; double average = sum / N;
3)複製數組函數
int N = a.length; double[] b = new double[N]; for (int i = 0; i < N; i++) b[i] = a[i];
4)反轉數組中元素oop
int N = a.length; for (int i = 0; i < N/2; i++) { double temp = a[i]; a[i] = a[N-i-1]; a[N-i-1] = temp; }
5)矩陣乘法性能
int N = a.length; double[][] c = new double[N][N]; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {// Compute dot product of row i and column j for (int k = 0; k < N; k++) c[i][j] += a[i][k]*b[k][j]; }
典型的靜態方法以下圖所示:測試
1)判斷是否爲素數網站
public static boolean isPrime(int N) { if (N < 2) return false; for (int N = 2; i*i <= N; i++) if (N % i == 0) return false; return true; }
2)計算調和級數
public static double H(int N) { double sum = 0.0; for (int i = 1; i < N; i++) sum += 1.0 / i; return sum; }
"<" 表示從文件讀取,">"表示寫入文件
數據類型是指一組值和一組對值的操做的集合,對象是可以存儲任意該數據類型的實體,或數據類型的實例。
一個數據類型的例子:
抽象數據類型和靜態方法的相同點:
不一樣點:
實例方法和靜態方法 :
Java中,全部非原始數據類型的值都是對象。對象的三大特性:狀態、標識、行爲。
引用 (reference) 是訪問對象的一種方式,如圖所示:
要建立 (或實例化) 一個對象,用關鍵字new並緊跟類名以及 () 來觸發它的構造函數。每當用例調用new (),系統都會:1. 爲新對象分配內存空間。 2. 調用構造函數初始化對象中的值。 3. 返回該對象的一個引用。
建立一個對象,並經過聲明語句將變量與對象的引用關聯起來:
組成部分:私有實例變量 (private instance variable),構造函數 (constructor),實例方法 (instance method) 和一個測試用例(client) 。
每一個Java類都至少含有一個構造函數以建立一個對象的標識。通常來講,構造函數的做用是初始化實例變量。若是沒有定義構造函數,類將會隱式將全部實例變量初始化爲默認值,原始數字類型默認值爲0,布爾型爲false,引用類型變量爲null。
在方法中調用實例變量,若出現二義性,可以使用 this 來區別:
鏈表是一種遞歸的數據結構,它或者爲空 (Null),或者是指向一個結點 (Node) 的引用,該結點包含一個泛型元素和一個指向另外一條鏈表的引用。
private class Node { Item item; Node next; }
一個Node對象包含兩個實例變量,類型分別爲Item (參數類型) 和Node,經過new Node () 觸發構造函數來建立一個Node類型的對象。調用的對象是一個指向Node對象的引用,它的實例變量均被初始化爲null。
構造一條含有元素to、be和or的鏈表,首先爲每一個元素建立結點:
Node first = new Node(); Node second = new Node(); Node third = new Node();
將每一個結點的item域設爲所需的值:
first.item = "to"; second.item = "be"; third.item = "or";
而後用next域構造鏈表:
first.next = second; second.next = third;
將first指向first.next:
通常數組a[] 的遍歷:
for (int i = 0; i < N; i++) { // Process a[i]. }
鏈表的遍歷:
for (Node x = first; x != null; x = x.next) { // Process x.item. }
棧是一種基於後進先出 (LIFO) 策略的集合類型。
public class Stack<Item> { private Node first; private int N; private class Node { Item item; Node next; } public boolean isEmpty() { return first == null; } public int size() { return N; } public void push(Item item) { Node oldfirst = first; first = new Node(); first.item = item; first.next = oldfirst; N++; } public Item pop() { Item item = first.item; first = first.next; N--; return item; } }
棧測試用例:
public static void main(String[] args) { // Create a stack and push/pop strings as directed on StdIn. Stack<String> s = new Stack<String>(); while (!StdIn.isEmpty()) { String item = StdIn.readString(); if (!item.equals("-")) s.push(item); else if (!s.isEmpty()) StdOut.print(s.pop() + " "); } StdOut.println("(" + s.size() + " left on stack)"); }
用鏈表實現棧的優勢:
隊列是一種基於先進先出(FIFO)策略的集合類型。
public class Queue<Item> { private Node first; private Node last; private int N; private class Node { Item item; Node next; } public boolean isEmpty() { return first == null; } public int size() { return N; } public void enqueue(Item item) { Node oldlast = last; last = new Node(); last.item = item; last.next = null; if (isEmpty()) first = last; else oldlast.next = last; N++; } public Item dequeue() { Item item = first.item; first = first.next; if (isEmpty()) last = null; N--; return item; } }
隊列測試用例:
public static void main(String[] args) { // Create a queue and enqueue/dequeue strings. Queue<String> q = new Queue<String>(); while (!StdIn.isEmpty()) { String item = StdIn.readString(); if (!item.equals("-")) q.enqueue(item); else if (!q.isEmpty()) StdOut.print(q.dequeue() + " "); } StdOut.println("(" + q.size() + " left on queue)"); }
揹包是一種不支持從中刪除元素的集合數據類型,它的目的是收集元素並迭代遍歷全部收集到的元素。使用揹包說明元素的處理順序不重要。
import java.util.Iterator; public class Bag<Item> implements Iterable<Item> { private Node first; private class Node { Item item; Node next; } public void add(Item item) { Node oldfirst = first; first = new Node(); first.item = item; first.next = oldfirst; } public Iterator<Item> iterator() { return new ListIterator(); } private class ListIterator implements Iterator<Item> { private Node current = first; public boolean hasNext() { return current != null; } public void remove() { } public Item next() { Item item = current.item; current = current.next; return item; } } }
基於Java中的currentTimeMillis() 方法,該方法能返回以毫秒計數的當前時間。
本書使用成本模型來評估算法的性質,這個模型定義了算法中的基本操做。例如3-sum問題的成本模型是訪問數組元素的次數。
1. 肯定輸入模型,定義問題的規模 2. 識別內循環 3. 根據內循環中的操做肯定成本模型 4. 對於給定的輸入,判斷這些操做的執行頻率