1. 程式人生 > >java一些必會演算法

java一些必會演算法


1.O表示法:粗略的量度方法即演算法的速度是如何與資料項的個數相關的

演算法                                                              O表示法表示的執行時間

線性查詢                                                              O(N)

二分查詢                                                              O(logN)

無序陣列的插入                                                        O(1)

有序陣列的插入                                                        O(N)

無序陣列的刪除                                                        O(N)

有序陣列的刪除                                                        O(N)

O(1)是最優秀的,O(logN)良好,O(N)還可以,O(N2)稍差(在冒泡法中見到)

2. 排序

 public class JWzw {
    //插入排序
    public void insertArray(Integer[] in ) {
        int tem = 0;
        int num = 0;
        int upnum = 0;
        for (int i = 0; i < in .length; i++) {
            for (int j = i - 1; j >= 0; j--) {
                num++;
                if ( in [j + 1] < in [j]) {
                    tem = in [j + 1]; in [j + 1] = in [j]; in [j] = tem;
                    upnum++;
                } else {
                    break;
                }
            }
        }
        for (int i = 0; i < in .length; i++) {
            System.out.print( in [i]);
            if (i < in .length - 1) {
                System.out.print(",");
            }
        }
        System.out.println();
        System.out.println("插入排序迴圈次數:" + num);
        System.out.println("移動次數:" + upnum);
        System.out.print("\n\n\n");
    }
    //選擇排序
    public void chooseArray(Integer[] in ) {
        int tem = 0;
        int num = 0;
        int upnum = 0;
        for (int i = 0; i < in .length; i++) {
            for (int j = 0; j < in .length - 1; j++) {
                num++;
                if ( in [j + 1] < in [j]) {
                    tem = in [j + 1]; in [j + 1] = in [j]; in [j] = tem;
                    upnum++;
                }
            }
        }
        for (int i = 0; i < in .length; i++) {
            System.out.print( in [i]);
            if (i < in .length - 1) {
                System.out.print(",");
            }
        }
        System.out.println();
        System.out.println("選擇排序迴圈次數:" + num);
        System.out.println("移動次數:" + upnum);
        System.out.print("\n\n\n");
    }
    //氣泡排序
    public void efferArray(Integer[] in ) {
        int tem = 0;
        int num = 0;
        int upnum = 0;
        for (int i = 0; i < in .length; i++) {
            for (int j = i; j < in .length - 1; j++) {
                num++;
                if ( in [j + 1] < in [i]) {
                    tem = in [j + 1]; in [j + 1] = in [i]; in [i] = tem;
                    upnum++;
                }
            }
        }
        for (int i = 0; i < in .length; i++) {
            System.out.print( in [i]);
            if (i < in .length - 1) {
                System.out.print(",");
            }
        }
        System.out.println();
        System.out.println("氣泡排序迴圈次數:" + num);
        System.out.println("移動次數:" + upnum);
        System.out.print("\n\n\n");
    }
    //列印乘法口訣
    public void printMulti() {
        for (int j = 1; j < 10; j++) {
            for (int i = 1; i <= j; i++) {
                System.out.print(i + " * " + j + " = " + j * i + "\t");
            }
            System.out.print("\t\n");
        }
        System.out.print("\n\n\n");
    }
    //列印N * 1 + N * 2 + N * 3 =num的所有組合
    public void printNumAssemble(int num) {
        for (int i = 0; i < num + 1; i++) {
            for (int j = 0; j < num / 2 + 1; j++) {
                for (int in = 0; in < num / 3 + 1; in ++) {
                    if (i * 1 + j * 2 + in * 3 == num) {
                        System.out.println("小馬" + i + ",\t中馬" + j + ",\t大馬" + in );
                    }
                }
            }
        }
    }
    /**

 * @param args

 */
    public static void main(String[] args) {
        JWzw jwzw = new JWzw();
        int num = 3;
        jwzw.printMulti(); //列印乘法口訣
        jwzw.printNumAssemble(100); //列印N * 1 + N * 2 + N * 3 =num的所有組合
        Integer in [] = {
            8, 89, 5, 84, 3, 45, 12, 33, 77, 98, 456, 878, 654, 213, 897
        };
        jwzw.efferArray( in ); //氣泡排序
        Integer in1[] = {
            8, 89, 5, 84, 3, 45, 12, 33, 77, 98, 456, 878, 654, 213, 897
        };
        jwzw.insertArray(in1); //插入排序
        Integer in2[] = {
            8, 89, 5, 84, 3, 45, 12, 33, 77, 98, 456, 878, 654, 213, 897
        };
        jwzw.chooseArray(in2); //選擇排序
        //int i = num++;
        //System.out.println(i);
        System.out.println(1000 >> 2);
    }
}

3. 優先順序佇列

class PriorityQueue {
    private long[] a = null;
    private int nItems = 0;
    private int maxSize = 0;
    public PriorityQueue(int maxSize) {
        a = new long[maxSize];
        this.maxSize = maxSize;
        nItems = 0;
    }
    public void insert(long l) {
        //優先順序佇列的插入不是隊尾,而是選擇一個合適的按照某種順序插入的
        //當佇列長度為0時,如下
        //不為0時,將所有比要插入的數小的資料後移,這樣大的數就在佇列的頭部了
        int i = 0;
        if (nItems == 0) {
            a[0] = l;
        } else {
            for (i = nItems - 1; i >= 0; i--) {
                if (l < a[i]) a[i + 1] = a[i];
                else break;
            }
            a[i + 1] = l;
        }
        nItems++;
    }
    public long remove() {
        //移出的是陣列最上端的數,這樣減少陣列元素的移動
        return a[--nItems];
    }
    public boolean isEmpty() {
        return (nItems == 0);
    }
    public boolean isFull() {
        return (nItems == maxSize);
    }
    public int size() {
        return nItems;
    }
}
public class duilie { // 佇列體類
    private duilie s;
    private String data;
    duilie(String data) {
        this.data = data;
    }
    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
    public duilie getS() {
        return s;
    }
    public void setS(duilie s) {
        this.s = s;
    }
}
public class duiliecz { // 佇列操作類
    /**

  * @param args

  */
    private int i = 0; // 佇列長
    private duilie top = new duilie(""); // 佇列頭
    private duilie end = new duilie(""); // 佇列尾
    public void add(String s) { // 新增佇列
        duilie m = new duilie(s);
        if (i != 0) {
            m.setS(top.getS());
            top.setS(m);
        } else {
            top.setS(m);
            end.setS(m);
        }
        i++;
    }


4. 佇列

public void del() { // 刪除隊尾
    if (i == 0) {
        return;
    } else if (i == 1) {
        top.setS(null);
        end.setS(null);
    } else {
        duilie top1 = new duilie(""); // 佇列底查詢用快取
        top1.setS(top.getS());
        while (!top1.getS().getS().equals(end.getS())) {
            top1.setS(top1.getS().getS());
        }
        end.setS(top1.getS());
    }
    i--;
}
public static void main(String[] args) {
    // TODO Auto-generated method stub
    duiliecz m = new duiliecz();
    m.add("1");
    m.add("2");
    m.add("3");
    m.add("4");
    for (int n = 0; n < 4; n++) {
        m.del();
    }
}
public int getI() {
    return i;
}
public duilie getEnd() {
    return end;
}
public duilie getTop() {
    return top;
}
}

5. 

public class Stack {
    int[] arr;
    int len = 0;
    public Stack() {
        arr = new int[100];
    }
    public Stack(int n) {
        arr = new int[n];
    }
    public int size() {
        return len + 1;
    }
    // 擴大陣列
    public void resize() {
        int[] b = new int[arr.length * 2];
        System.arraycopy(arr, 0, b, 0, arr.length);
        arr = b;
    }
    public void show() {
        for (int i = 0; i < len; i++) {
            System.out.print(arr[i] + "  ");
        }
        System.out.println();
    }
    // 進棧
    public void push(int a) {
        if (len >= arr.length) resize();
        arr[len] = a;
        len++;
    }
    // 出棧
    public int pop() {
        if (len == 0) {
            System.out.println();
            System.out.println("stack is empty!");
            return -1;
        }
        int a = arr[len - 1];
        arr[len - 1] = 0;
        len--;
        return a;
    }
}

6. 連結串列

class Node {
    Object data;
    Node next;
    public Node(Object data) {
        setData(data);
    }
    public void setData(Object data) {
        this.data = data;
    }
    public Object getData() {
        return data;
    }
}
class Link {
    Node head;
    int size = 0;
    public void add(Object data) {
        Node n = new Node(data);
        if (head == null) {
            head = n;
        } else {
            Node current = head;
            while (true) {
                if (current.next == null) {
                    break;
                }
                current = current.next;
            }
            current.next = n;
        }
        size++;
    }
    public void show() {
        Node current = head;
        if (current != null) {
            while (true) {
                System.out.println(current);
                if (current == null) {
                    break;
                }
                current = current.next;
            }
        } else {
            System.out.println("link is empty");
        }
    }
    public Object get(int index) {
        // ....
    }
    public int size() {
        return size;
    }
}


7. 單鏈表

class Node // 節點類,單鏈表上的節點
{
    String data; // 資料域,存放String類的資料
    Node next; // 指向下一個節點
    Node(String data) {
        this.data = data; // 建構函式
    }
    String get() {
        return data; // 返回資料
    }
}
class MyLinkList // 連結串列類
{
    Node first; // 頭節點
    int size; // 連結串列長度
    MyLinkList(String arg[]) {
        // Node first = new Node("head");//生成頭節點
        first = new Node("head"); // J.F. 這裡不需要定義區域性變數 first
        // 如果定義了局部變數,那成員變數 first 就一直沒有用上
        // 所以,它一直為空
        size = 0;
        Node p = first;
        for (int i = 0; i < arg.length; i++) // 將arg陣列中的元素分別放入連結串列中
        {
            Node q = new Node(arg[i]);
            q.next = p.next; // 每一個節點存放一個arg陣列中的元素
            p.next = q;
            p = p.next;
            size++;
        }
    }
    MyLinkList() // 無引數建構函式
    {
        // Node first = new Node("head");
        first = new Node("head"); // J.F. 這裡犯了和上一個構造方法同樣的錯誤
        size = 0;
    }
    int size() // 返回連結串列長度
    {
        return size;
    }
    void insert(Node a, int index) // 將節點a 插入連結串列中的第index個位置
    {
        Node temp = first;
        for (int i = 0; i < index; i++) {
            temp = temp.next; // 找到插入節點的前一節點
        }
        a.next = temp.next; // 插入節點
        temp.next = a;
        size++;
    }
    Node del(int index) // 刪除第index個節點,並返回該值
    {
        Node temp = first;
        for (int i = 0; i < index; i++) {
            temp = temp.next; // 找到被刪除節點的前一節點
        }
        Node node = temp.next;
        temp.next = node.next;
        size--; // 刪除該節點,連結串列長度減一
        return node;
    }
    void print() // 在螢幕上輸出該連結串列(這段程式總是出錯,不知道錯在哪裡)
    {
        Node temp = first;
        for (int i = 1; i < size; i++) // 將各個節點分別在螢幕上輸出
        {
            temp = temp.next;
            System.out.print(temp.get() + "->");
        }
    }
    void reverse() // 倒置該連結串列
    {
        for (int i = 0; i < size; i++) {
            insert(del(size - 1), 0); // 將最後一個節點插入到最前
            // J.F. 最後一個節點的 index 應該是 size - 1
            // 因為第一個節點的 index 是 0
        }
    }
    String get(int index) // 查詢第index個節點,返回其值
    {
        if (index >= size) {
            return null;
        }
        Node temp = first;
        for (int i = 0; i < index; i++) {
            temp = temp.next; // 找到被查詢節點的前一節點
        }
        return temp.next.get();
    }
}
class MyStack // 堆疊類,用單鏈表實現
{
    MyLinkList tmp;
    Node temp;
    MyStack() {
        // MyLinkList tmp = new MyLinkList();
        tmp = new MyLinkList(); // J.F. 和 MyLinkList 構造方法同樣的錯誤
    }
    void push(String a) // 壓棧,即往連結串列首部插入一個節點
    {
        Node temp = new Node(a);
        tmp.insert(temp, 0);
    }
    String pop() // 出棧,將連結串列第一個節點刪除
    {
        Node a = tmp.del(0);
        return a.get();
    }
    int size() {
        return tmp.size();
    }
    boolean empty() // 判斷堆疊是否為空
    {
        if (tmp.size() == 0) return false;
        else return true;
    }
}
public class MyLinkListTest // 測試程式部分
{
    public static void main(String arg[]) // 程式入口
    {
        if ((arg.length == 0) || (arg.length > 10)) System.out.println("長度超過限制或者缺少引數");
        else {
            MyLinkList ll = new MyLinkList(arg); // 建立一個連結串列
            ll.print(); // 先輸出該連結串列(執行到這一步丟擲異常)
            ll.reverse(); // 倒置該連結串列
            ll.print(); // 再輸出倒置後的連結串列
            String data[] = new String[10];
            int i;
            for (i = 0; i < ll.size(); i++) {
                data[i] = ll.get(i); // 將連結串列中的資料放入陣列
            }
            // sort(data);// 按升序排列data中的資料(有沒有現成的排序函式?)
            for (i = 0; i < ll.size(); i++) {
                System.out.print(data[i] + ";"); // 輸出陣列中元素
            }
            System.out.println();
            MyStack s = new MyStack(); // 建立堆疊例項s
            for (i = 0; i < ll.size(); i++) {
                s.push(data[i]); // 將陣列元素壓棧
            }
            while (!s.empty()) {
                System.out.print(s.pop() + ";"); // 再將堆疊裡的元素彈出
            }
        }
    }
}


8. 雙端連結串列

class Link {
    public int iData = 0;
    public Link next = null;
    public Link(int iData) {
        this.iData = iData;
    }
    public void display() {
        System.out.print(iData + " ");
    }
}
class FirstLastList {
    private Link first = null;
    private Link last = null;
    public FirstLastList() {
        first = null;
        last = null;
    }
    public void insertFirst(int key) {
        Link newLink = new Link(key);
        if (this.isEmpty()) last = newLink;
        newLink.next = first;
        first = newLink;
    }
    public void insertLast(int key) {
        Link newLink = new Link(key);
        if (this.isEmpty()) first = newLink;
        else last.next = newLink;
        last = newLink;
    }
    public Link deleteFirst() {
        Link temp = first;
        if (first.next == null) last = null;
        first = first.next;
        return temp;
    }
    public boolean isEmpty() {
        return (first == null);
    }
    public void displayList() {
        System.out.print("List (first-->last): ");
        Link current = first;
        while (current != null) {
            current.display();
            current = current.next;
        }
        System.out.println("");
    }
}
class FirstLastListApp {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        FirstLastList theList = new FirstLastList();
        theList.insertFirst(22); // insert at front
        theList.insertFirst(44);
        theList.insertFirst(66);
        theList.insertLast(11); // insert at rear
        theList.insertLast(33);
        theList.insertLast(55);
        theList.displayList(); // display the list
        theList.deleteFirst(); // delete first two items
        theList.deleteFirst();
        theList.displayList(); // display again
    }
}


9. 有序連結串列

package arithmetic;
class Link {
    public int iData = 0;
    public Link next = null;
    public Link(int iData) {
        this.iData = iData;
    }
    public void display() {
        System.out.print(iData + " ");
    }
}
class SortedList {
    private Link first = null;
    public SortedList() {
        first = null;
    }
    public void insert(int key) {
        Link newLink = new Link(key);
        Link previous = null;
        Link current = first;
        // while的第一個條件是沒有到達連結串列的尾端,第二個是按順序找到一個合適的位置
        while (current != null && key > current.iData) {
            previous = current;
            current = current.next;
        }
        // 如果是空表或者要插入的元素最小,則在表頭插入key
        if (current == first) first = newLink;
        else previous.next = newLink;
        newLink.next = current;
    }
    /**

 * 刪除表頭的節點

 *

 * @return 要刪除的節點

 */
    public Link remove() {
        Link temp = first;
        first = first.next;
        return temp;
    }
    public boolean isEmpty() {
        return (first == null);
    }
    public void displayList() {
        System.out.print("List (first-->last): ");
        Link current = first; // start at beginning of list
        while (current != null) // until end of list,
        {
            current.display(); // print data
            current = current.next; // move to next link
        }
        System.out.println("");
    }
}
class SortedListApp {
    public static void main(String[] args) { // create new list
        SortedList theSortedList = new SortedList();
        theSortedList.insert(20); // insert 2 items
        theSortedList.insert(40);
        theSortedList.displayList(); // display list
        theSortedList.insert(10); // insert 3 more items
        theSortedList.insert(30);
        theSortedList.insert(50);
        theSortedList.displayList(); // display list
        theSortedList.remove(); // remove an item
        theSortedList.displayList(); // display list
    }
}


10. 雙向連結串列

class Link {
    // 雙向連結串列,有兩個指標,一個向前,一個向後
    public int iData = 0;
    public Link previous = null;
    public Link next = null;
    public Link(int iData) {
        this.iData = iData;
    }
    public void display() {
        System.out.print(iData + " ");
    }
}
class DoublyLinked {
    // 分別指向連結串列的表頭和表尾
    private Link first = null;
    private Link last = null;
    public boolean isEmpty() {
        return first == null;
    }
    /**

 * 在表頭插入資料

 *

 * @param 要插入的節點的資料

 */
    public void insertFirst(int key) {
        Link newLink = new Link(key);
        // 如果開始連結串列為空,則插入第一個資料後,last也指向第一個資料
        if (this.isEmpty()) last = newLink;
        else { // 表不為空的情況
            first.previous = newLink;
            newLink.next = first;
        }
        // 無論怎樣,插入後都的讓first重新指向第一個節點
        first = newLink;
    }
    public void insertLast(int key) { // 在尾端插入資料,同上
        Link newLink = new Link(key);
        if (this.isEmpty()) first = newLink;
        else {
            last.next = newLink;
            newLink.previous = last;
        }
        last = newLink;
    }
    /**

 * 在指定的節點後插入資料

 *

 * @param key

 *            指定的節點的值

 * @param iData

 *            要插入的資料

 * @return 是否插入成功

 */
    public boolean insertAfter(int key, int iData) {
        Link newLink = new Link(key);
        Link current = first;
        // 從first開始遍歷,看能否找到以key為關鍵字的節點
        while (current.iData != key) {
            current = current.next;
            // 若能找到就跳出迴圈,否則返回false,插入失敗
            if (current == null) return false;
        }
        // 如果插入點在last的位置
        if (current == last) {
            last = newLink;
        } else { // 非last位置,交換各個next和previous的指標
            newLink.next = current.next;
            current.next.previous = newLink;
        }
        current.next = newLink;
        newLink.previous = current;
        return true;
    }
    /**

 * 刪除表頭的節點

 *

 * @return

 */
    public Link deleteFirst() {
        Link temp = first;
        // 如果表中只有一個元素,刪除後則為空表,所以last=null
        if (first.next == null) last = null;
        else
        // 否則,讓第二個元素的previous=null
            first.next.previous = null;
        // 刪除頭指標,則first指向原來的second
        first = first.next;
        return temp;
    }
    public Link deleteLast() { // 同上
        Link temp = last;
        if (last.previous == null) first = null;
        else last.previous.next = null;
        last = last.previous;
        return temp;
    }
    public Link deleteKey(int key) {
        Link current = first;
        // 遍歷整個連結串列查詢對應的key,如果查到跳出迴圈,否則...
        while (current.iData != key) {
            current = current.next;
            // ...否則遍歷到表尾,說明不存在此key,返回null,刪除失敗
            if (current == null) return null;
        }
        if (current == first) first = first.next;
        else current.previous.next = current.next;
        if (current == last) last = last.previous;
        else current.next.previous = current.previous;
        return current;
    }
    public void displayForward() {
        Link current = first;
        while (current != null) {
            current.display();
            current = current.next;
        }
        System.out.println();
    }
    public void displayBackward() {
        Link current = last;
        while (current != null) {
            current.display();
            current = current.previous;
        }
        System.out.println();
    }
}
class DoublyLinkedApp {
    public static void main(String[] args) { // make a new list
        DoublyLinked theList = new DoublyLinked();
        theList.insertFirst(22); // insert at front
        theList.insertFirst(44);
        theList.insertFirst(66);
        theList.insertLast(11); // insert at rear
        theList.insertLast(33);
        theList.insertLast(55);
        theList.displayForward(); // display list forward
        theList.displayBackward(); // display list backward
        theList.deleteFirst(); // delete first item
        theList.deleteLast(); // delete last item
        theList.deleteKey(11); // delete item with key 11
        theList.displayForward(); // display list forward
        theList.insertAfter(22, 77); // insert 77 after 22
        theList.insertAfter(33, 88); // insert 88 after 33
        theList.displayForward(); // display list forward
    }
}


11. 實現二叉樹前序遍歷迭代器

class TreeNode這個類用來宣告樹的結點,其中有左子樹、右子樹和自身的內容。
class MyTree這個類用來宣告一棵樹,傳入根結點。這裡設計的比較簡單
class TreeEum這個類是樹的迭代器,通過 MyTree類的方法獲取,這裡主要就是設計它了。程式碼如下:
//TreeNode類,使用了泛型,由於比較簡單,考試.大提示不作解釋
   class TreeNode < E > {
    E node;  
    private TreeNode < String > left;  
    private TreeNode < String > right;  
    public TreeNode(E e) {  
        this(e, null, null);
    }  
    public TreeNode(E e, TreeNode < String > left, TreeNode < String > right) {  
        this.node = e;  
        this.left = left;  
        this.right = right;
    }  
    public TreeNode < String > left() {  
        return left;
    }  
    public TreeNode < String > right() {  
        return right;
    }
}
// MyTree類,沒什麼功能,傳入根結點構造,getEnumerator()方法獲取迭代器。
  
class MyTree {
    TreeNode < String > root;  
    public MyTree(TreeNode < String > root) {  
        this.root = root;
    }  
    public TreeEnum getEnumerator() {  
        return new TreeEnum(root);
    }
}
// 這個類為迭代器,有詳細解釋,相信各位能看懂。在棧中用了兩次泛型。
  
import java.util.Stack;  
public class TreeEnum {  
    private TreeNode < String > root;  
    private Stack < TreeNode < String >> store; /* 儲存遍歷左子樹但未遍歷右子樹的結點 */   
    private TreeNode < String > next;  
    public TreeEnum(TreeNode < String > root) {  
        this.root = root;
        store = new Stack < TreeNode < String >> ();
        next = root;
    }  
    public TreeNode < String > next() {
        TreeNode < String > current = next;  
        if (next != null) {
            /* 如果當前結點的左子樹不為空,則遍歷左子樹,並標記當前結點未遍歷右子樹 */
              
            if (next.left() != null) {
                store.push(next);
                next = next.left();
            }
            // 如果當前結點的左子樹為空,則遍歷右子樹
              
            else if (next.right() != null) {
                next = next.right();
            }
            /* 如果當前結點為葉子,則找未遍歷右子樹的結點並且遍歷它的右子樹 */
              
            else {  
                if (!store.empty()) /* 判斷是否還有結點的右子樹未遍歷 */ {
                    TreeNode < String > tmp = store.pop();
                    /* 如果有未遍歷右子樹的結點,但它的右子樹為空,且還有結點的右子樹未遍歷, */
                    /* 則一直往上取,直到取到未遍歷右子樹且右子樹不為空的結點,遍歷它的右子樹. */
                      
                    while ((tmp.right() == null) && !store.empty()) {
                        tmp = store.pop();
                    }
                    next = tmp.right();
                }  
                else {
                    /* 如果沒有哪個結點右子樹未遍歷,則表示沒有下一個結點了,設定next為null */
                    next = null;
                }
            }
        }  
        return current;
    }  
    public boolean hasMoreElement() {  
        return next != null;
    }
}  下面寫個測試類,不作解釋,相信大家看得懂  
public class TreeReader {  
    public static void main(String[] args) {
        TreeNode < String > n1 = new TreeNode < String > ("n1");
        TreeNode < String > n2 = new TreeNode < String > ("n2");
        TreeNode < String > n3 = new TreeNode < String > ("n3");
        TreeNode < String > n4 = new TreeNode < String > ("n4");
        TreeNode < String > n5 = new TreeNode < String > ("n5");
        TreeNode < String > n6 = new TreeNode < String > ("n6", null, n1);
        TreeNode < String > n7 = new TreeNode < String > ("n7", n2, null);
        TreeNode < String > n8 = new TreeNode < String > ("n8", n7, null);
        TreeNode < String > n9 = new TreeNode < String > ("n9", null, n5);
        TreeNode < String > n10 = new TreeNode < String > ("n10", n4, n9);
        TreeNode < String > n11 = new TreeNode < String > ("n11", n6, n8);
        TreeNode < String > n12 = new TreeNode < String > ("n12", n3, n10);
        TreeNode < String > root = new TreeNode < String > ("root", n11, n12);
        MyTree tree = new MyTree(root);
        TreeEnum eum = tree.getEnumerator();  
        while (eum.hasMoreElement()) {
            System.out.print(eum.next().node + "--");
        }
        System.out.println("end");
    }
}


12. 迭代器

package TreeIterator;
public interface Iterator {
    public boolean hasNext();
    public Object next();
}這個介面我們有
2個方法, hasNext()是否還有下一條資料, next返回具體的 Object這裡也就是樹。我們先不必要忙著做他的實現類,我們現在要來做的是這個容器(不是 JAVA中容器,與 arraylist什麼的無關),正所謂樹的容器是什麼,是山也!我們想想山應該具有什麼呢!?首先它要有種植樹的功能,這裡可以看作新增樹。我們可以想像山的功能是和樹相互關聯的,那麼他們之間是什麼關係呢,我們給他們一種聚合的關係,聚合的關係大家可以參考 UML圖,我在這裡給出它的一種程式表現形式。
package TreeIterator;
public class Hall {
    Tree[] tree; // 這裡可以看作是聚合關係
    private int index; // 指向Tree[]的標籤
    public Hall(int maxNumber) {
        tree = new Tree[maxNumber];
        index = 0;
    }
    public void add(Tree tree) {
        this.tree[index] = tree;
        index++;
    }
    public Iterator connectIterator() {
        return new TreeIterator(this);
    }
}

這裡我們定義的山可以抽象出
Hall類來, Tree[] tree可以看作是山和樹之間的一種聚合關係。 add方法就是新增樹。問題來了,山和樹有了關係,那麼山和迭代器有什麼關係呢。它們之間肯定有一種關係。我們有了這個容器(山),就要把這個容器來實現迭代的方法: hasNext()和 Next().恩這裡我們可以看出,山和迭代器之間也是一種關聯關係。我們就把它看成是一種聚合關係(TIP:聚合關係一種特殊的關聯關係)。我們可以通過一個 connectIterator方法來連結山和迭代器,接下來我們要去做一個具體的迭代類,這個具體的類中間有了 hasNext()和 Next()的具體實現方法

package TreeIterator;
public class TreeIterator implements Iterator {
    private int last = 0;
    private Hall hall;
    public TreeIterator(Hall hall) {
        this.hall = hall;
    }
    public boolean hasNext() {
        if (last < hall.tree.length) return true;
        else return false;
    }
    public Tree next() {
        Tree t = hall.tree[last];
        last++;
        return t;
    }
}


這裡Hall hall就可以看作是一種關聯關係,我們要把山和迭代器聯絡起來就通過建構函式來實現, hasNext和 next實現方法就體現出來了有了山,有了迭代器,可是樹還沒有定義,不過這個樹的方法還很好解決!樹不關聯其他的事務,我們可以簡單的這麼寫:

package TreeIterator;
public class Tree {
    private String name;
    public Tree(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
}

好了似乎我們整個工程完工了,我們現在來模擬一下農民老大伯來種樹撒肥的過程;

package TreeIterator;
public class Pren {
    public Pren() {}
    public static void main(String[] args) {
        Hall hall = new Hall(4);
        hall.add(new Tree("蘋果樹"));
        hall.add(new Tree("梨樹"));
        hall.add(new Tree("橘子樹"));
        hall.add(new Tree("鳳梨樹"));
        for (Iterator i = hall.connectIterator(); i.hasNext();) {
            String Type = ((Tree)(i.next())).getName();
            if (Type == "蘋果樹") {
                System.out.println("灑蘋果樹的農藥,");
            }
            if (Type == "梨樹") {
                System.out.println("灑梨樹的農藥");
            }
            if (Type == "橘子樹") {
                System.out.println("灑橘子樹的農藥,灑了也沒用,還沒到成熟日,現在沒結果實");
            }
            if (Type == "鳳梨樹") {
                System.out.println("南風天,溼氣大,讓它爛在地裡吧");
            }
        }
    }
}
種4個樹,山小而五臟俱全,更像一個土包,再要有樹才行啊,所以 4個樹的例項出現。好了接下來種樹,幾毫秒解決!山了有我們就要把山放到迭代器中間去了。遍歷這個山(容器)。聯想我們看看 arrayList中的迭代器模式是怎麼實現的!
ArrayList a = new ArrayList();
a.add("a1");
a.add("a2");
a.add("a3");
a.add("a4");
for (Iterator i = a.iterator(); i.hasNext();) {
    System.out.println(i.next().toString());
}


13. 合併搜尋演算法

public class MergeSortArray {
    private long[] theArray;
    private int nElems;
    public MergeSortArray(int max) {
        theArray = new long[max];
        nElems = 0;
    }
    public void insert(long value) {
        theArray[nElems] = value; // insert it
        nElems++; // increment size
    }
    public void display() {
        for (int j = 0; j < nElems; j++) System.out.print(theArray[j] + " ");
        System.out.println("");
    }
    public void mergeSort() {
        long[] workSpace = new long[nElems];
        recMergeSort(workSpace, 0, nElems - 1);
    }
    private void recMergeSort(long[] workSpace, int lowerBound, int upperBound) {
        if (lowerBound == upperBound) // if range is 1,
            return; // no use sorting
        else { // find midpoint
            int mid = (lowerBound + upperBound) / 2;
            // sort low half
            recMergeSort(workSpace, lowerBound, mid);
            // sort high half
            recMergeSort(workSpace, mid + 1, upperBound);
            // merge them
            merge(workSpace, lowerBound, mid + 1, upperBound);
        }
    }
    private void merge(long[] workSpace, int lowPtr, int highPtr, int upperBound) {
        int j = 0; // workspace index
        int lowerBound = lowPtr;
        int mid = highPtr - 1;
        int n = upperBound - lowerBound + 1; // # of items
        while (lowPtr <= mid && highPtr <= upperBound)
            if (theArray[lowPtr] < theArray[highPtr]) workSpace[j++] = theArray[lowPtr++];
            else workSpace[j++] = theArray[highPtr++];
        while (lowPtr <= mid) workSpace[j++] = theArray[lowPtr++];
        while (highPtr <= upperBound) workSpace[j++] = theArray[highPtr++];
        for (j = 0; j < n; j++) theArray[lowerBound + j] = workSpace[j];
    }
    public static void main(String[] args) {
        int maxSize = 100; // array size
        MergeSortArray arr = new MergeSortArray(maxSize); // create the array
        arr.insert(14);
        arr.insert(21);
        arr.insert(43);
        arr.insert(50);
        arr.insert(62);
        arr.insert(75);
        arr.insert(14);
        arr.insert(2);
        arr.insert(39);
        arr.insert(5);
        arr.insert(608);
        arr.insert(36);
        arr.display();
        arr.mergeSort();
        arr.display();
    }
}


14. 遞迴

public class Recursion {
   
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Recursion re = new Recursion();
        System.out.println(re.RecursionNum(10));
    }
    public int RecursionNum(int num) {
        if (num > 0) {
            return num + RecursionNum(num - 1);
        }
        Else {
            return 0;
        }
    }
}


15. 歸併排序

/**

 * 歸併排序,要求待排序的陣列必須實現Comparable介面

 */
public class MergeSort implements SortStrategy {
    private Comparable[] bridge;
    /**

 * 利用歸併排序演算法對陣列obj進行排序

 */
    public void sort(Comparable[] obj) {
        if (obj == null) {
            throw new NullPointerException("The param can not be null!");
        }
        bridge = new Comparable[obj.length]; // 初始化中間陣列
        mergeSort(obj, 0, obj.length - 1); // 歸併排序
        bridge = null;
    }
    /**

 * 將下標從left到right的陣列進行歸併排序

 *

 * @param obj

 *            要排序的陣列的控制代碼

 * @param left

 *            要排序的陣列的第一個元素下標

 * @param right

 *            要排序的陣列的最後一個元素的下標

 */
    private void mergeSort(Comparable[] obj, int left, int right) {
        if (left < right) {
            int center = (left + right) / 2;
            mergeSort(obj, left, center);
            mergeSort(obj, center + 1, right);
            merge(obj, left, center, right);
        }
    }
    /**

 * 將兩個物件陣列進行歸併,並使歸併後為升序。歸併前兩個陣列分別有序

 *

 * @param obj

 *            物件陣列的控制代碼

 * @param left

 *            左陣列的第一個元素的下標

 * @param center

 *            左陣列的最後一個元素的下標

 * @param right

 *            右陣列的最後一個元素的下標

 */
    private void merge(Comparable[] obj, int left, int center, int right) {
        int mid = center + 1;
        int third = left;
        int tmp = left;
        while (left <= center && mid <= right) { // 從兩個陣列中取出小的放入中間陣列
            if (obj[left].compareTo(obj[mid]) <= 0) {
                bridge[third++] = obj[left++];
            } else bridge[third++] = obj[mid++];
        }
        // 剩餘部分依次置入中間陣列
        while (mid <= right) {
            bridge[third++] = obj[mid++];
        }
        while (left <= center) {
            bridge[third++] = obj[left++];
        }
        // 將中間陣列的內容拷貝回原陣列
        copy(obj, tmp, right);
    }
    /**

 * 將中間陣列bridge中的內容拷貝到原陣列中

 *

 * @param obj

 *            原陣列的控制代碼

 * @param left

 *            要拷貝的第一個元素的下標

 * @param right

 *            要拷貝的最後一個元素的下標

 */
    private void copy(Comparable[] obj, int left, int right) {
        while (left <= right) {
            obj[left] = bridge[left];
            left++;
        }
    }
}


16. 希爾排序

間隔序列:
h = 3 * h + 1, h = (h - 1) / 3
public class ShellSort {
    /**

 * @param args

 */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ShellSort ss = new ShellSort();
        int num[] = {
            546, 87, 21, 3124, 65, 2, 9, 3, 213, 54, 98, 23, 6, 4, 7,
            8, 123, 872, 61, 5, 8954
        };
        ss.shellArray(num);
        for (int i = 0; i < num.length; i++) {
            System.out.println(num[i]);
        }
    }
    public void shellArray(int[] num) {
        int i = 1;
        int tem, in ;
        for (; i < num.length / 3;) {
            i = 3 * i + 1;
        }
        for (; i >= 1;) {
            for (int j = i; j < num.length; j++) {
                tem = num[j]; in = j;
                while ( in > i - 1 && num[ in -i] >= tem) {
                    num[ in ] = num[ in -i]; in = in -i;
                }
                num[ in ] = tem;
            }
            i = (i - 1) / 3;
        }
    }
}


17. 快速排序

class QuickSort {
    private int[] data;
    QuickSort(int[] data) {
        this.data = data;
    }
    public void quickSort() {
        recQuickSort(data, 0, data.length - 1);
    }
    private void recQuickSort(int[] data, int low, int high) {
        // 設定兩個滑標
        int lowCursor = low + 1;
        int highCursor = high;
        // 交換時的臨時變數
        int temp = 0;
        // 比較樞值,設為陣列的第一個值
        int medi = data[low];
        while (true) {
            // 從低端開始查詢,確定大於數 data[low] 所在的位置
            while (lowCursor < high && data[lowCursor] < medi) {
                lowCursor++;
            }
            // 從高階開始查詢,確定小於數 data[low] 所在的位置。這裡要使用 >= 判斷確定小於值
            while (highCursor > low && data[highCursor] >= medi) {
                highCursor--;
            }
            // 兩遊標位置出現越界,退出迴圈
            if (lowCursor >= highCursor) {
                break;
            }
            // 交換 data[highCursor] 和 data[lowCursor] 位置資料
            temp = data[highCursor];
            data[highCursor] = data[lowCursor];
            data[lowCursor] = temp;
        }
        // 由 while 迴圈退出條件可知:lowCursor > highCursor
        // 當前 lowCursor 指向右側大於 data[low]的第一個位置;
        // 而 highCursor 指向左側小於 data[low]的第一個位置,所以需要交換 data[low] 和
        // data[highCursor]的值
        data[low] = data[highCursor];
        data[highCursor] = medi;
        // 遞迴運算左半部分
        if (low < highCursor) {
            recQuickSort(data, low, highCursor);
        }
        // 遞迴運算右半部分
        if (lowCursor < high) {
            recQuickSort(data, lowCursor, high);
        }
    }
    public void display() {
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        int[] data = new int[] {
            43, 12, 32, 55, 33, 67, 54, 65, 43, 22, 66,
            98, 74
        };
        QuickSort sort = new QuickSort(data);
        sort.display();
        sort.quickSort();
        sort.display();
    }
}


18. 二叉樹

//******************************************************************************************************//
//*****本程式包括簡單的二叉樹類的實現和前序,中序,後序,層次遍歷二叉樹演算法,*******//
//******以及確定二叉樹的高度,制定物件在樹中的所處層次以及將樹中的左右***********//
//******孩子節點對換位置,返回葉子節點個數刪除葉子節點,並輸出所刪除的葉子節點**//
//*******************************CopyRight By phoenix*******************************************//
//************************************Jan 12,2008*************************************************//
//****************************************************************************************************//
public class BinTree {
    public final static int MAX = 40;
    BinTree[] elements = new BinTree[MAX]; // 層次遍歷時儲存各個節點
    int front; // 層次遍歷時隊首
    int rear; // 層次遍歷時隊尾
    private Object data; // 資料元數
    private BinTree left, right; // 指向左,右孩子結點的鏈
    public BinTree() {}
    public BinTree(Object data) { // 構造有值結點
        this.data = data;
        left = right = null;
    }
    public BinTree(Object data, BinTree left, BinTree right) { // 構造有值結點
        this.data = data;
        this.left = left;
        this.right = right;
    }
    public String toString() {
        return data.toString();
    }
    // 前序遍歷二叉樹
    public static void preOrder(BinTree parent) {
        if (parent == null) return;
        System.out.print(parent.data + " ");
        preOrder(parent.left);
        preOrder(parent.right);
    }
    // 中序遍歷二叉樹
    public void inOrder(BinTree parent) {
        if (parent == null) return;
        inOrder(parent.left);
        System.out.print(parent.data + " ");
        inOrder(parent.right);
    }
    // 後序遍歷二叉樹
    public void postOrder(BinTree parent) {
        if (parent == null) return;
        postOrder(parent.left);
        postOrder(parent.right);
        System.out.print(parent.data + " ");
    }
    // 層次遍歷二叉樹
    public void LayerOrder(BinTree parent) {
        elements[0] = parent;
        front = 0;
        rear = 1;
        while (front < rear) {
            try {
                if (elements[front].data != null) {
                    System.out.print(elements[front].data + " ");
                    if (elements[front].left != null) elements[rear++] = elements[front].left;
                    if (elements[front].right != null) elements[rear++] = elements[front].right;
                    front++;
                }
            } catch (Exception e) {
                break;
            }
        }
    }
    // 返回樹的葉節點個數
    public int leaves() {
        if (this == null) return 0;
        if (left == null && right == null) return 1;
        return (left == null ? 0 : left.leaves()) + (right == null ? 0 : right.leaves());
    }
    // 結果返回樹的高度
    public int height() {
        int heightOfTree;
        if (this == null) return -1;
        int leftHeight = (left == null ? 0 : left.height());
        int rightHeight = (right == null ? 0 : right.height());
        heightOfTree = leftHeight < rightHeight ? rightHeight : leftHeight;
        return 1 + heightOfTree;
    }
    // 如果物件不在樹中,結果返回-1;否則結果返回該物件在樹中所處的層次,規定根節點為第一層
    public int level(Object object) {
        int levelInTree;
        if (this == null) return -1;
        if (object == data) return 1; // 規定根節點為第一層
        int leftLevel = (left == null ? -1 : left.level(object));
        int rightLevel = (right == null ? -1 : right.level(object));
        if (leftLevel < 0 && rightLevel < 0) return -1;
        levelInTree = leftLevel < rightLevel ? rightLevel : leftLevel;
        return 1 + levelInTree;
    }
    // 將樹中的每個節點的孩子對換位置
    public void reflect() {
        if (this == null) return;
        if (left != null) left.reflect();
        if (right != null) right.reflect();
        BinTree temp = left;
        left = right;
        right = temp;
    }
    // 將樹中的所有節點移走,並輸出移走的節點
    public void defoliate() {
        if (this == null) return;
        // 若本節點是葉節點,則將其移走
        if (left == null && right == null) {
            System.out.print(this + " ");
            data = null;
            return;
        }
        // 移走左子樹若其存在
        if (left != null) {
            left.defoliate();
            left = null;
        }
        // 移走本節點,放在中間表示中跟移走...
        // innerNode += this + " ";
        data = null;
        // 移走右子樹若其存在
        if (right != null) {
            right.defoliate();
            right = null;
        }
    }
    /**

 * @param args

 */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        BinTree e = new BinTree("E");
        BinTree g = new BinTree("G");
        BinTree h = new BinTree("H");
        BinTree i = new BinTree("I");
        BinTree d = new BinTree("D", null, g);
        BinTree f = new BinTree("F", h, i);
        BinTree b = new BinTree("B", d, e);
        BinTree c = new BinTree("C", f, null);
        BinTree tree = new BinTree("A", b, c);
        System.out.println("前序遍歷二叉樹結果: ");
        tree.preOrder(tree);
        System.out.println();
        System.out.println("中序遍歷二叉樹結果: ");
        tree.inOrder(tree);
        System.out.println();
        System.out.println("後序遍歷二叉樹結果: ");
        tree.postOrder(tree);
        System.out.println();
        System.out.println("層次遍歷二叉樹結果: ");
        tree.LayerOrder(tree);
        System.out.println();
        System.out.println("F所在的層次: " + tree.level("F"));
        System.out.println("這棵二叉樹的高度: " + tree.height());
        System.out.println("--------------------------------------");
        tree.reflect();
        System.out.println("交換每個節點的孩子節點後......");
        System.out.println("前序遍歷二叉樹結果: ");
        tree.preOrder(tree);
        System.out.println();
        System.out.println("中序遍歷二叉樹結果: ");
        tree.inOrder(tree);
        System.out.println();
        System.out.println("後序遍歷二叉樹結果: ");
        tree.postOrder(tree);
        System.out.println();
        System.out.println("層次遍歷二叉樹結果: ");
        tree.LayerOrder(tree);
        System.out.println();
        System.out.println("F所在的層次: " + tree.level("F"));
        System.out.println("這棵二叉樹的高度: " + tree.height());
    }
}


經典演算法的Java實現

1)河內塔問題:

說明:

河內之塔(Towers of Hanoi)是法國人M.Claus(Lucas)於1883年從泰國帶至法國的,河內為越戰時北越的首都,即現在的胡志明市;1883年法國數學家 Edouard Lucas曾提及這個故事,據說創世紀時Benares有一座波羅教塔,是由三支鑽石棒(Pag)所支撐,開始時神在第一根棒上放置64個由上至下依由小至大排列的金盤(Disc),並命令僧侶將所有的金盤從第一根石棒移至第三根石棒,且搬運過程中遵守大盤子在小盤子之下的原則,若每日僅搬一個盤子,則當盤子全數搬運完畢之時,此塔將毀損,而也就是世界末日來臨之時。

解法:

如果柱子標為ABC,要由A搬至C,在只有一個盤子時,就將它直接搬至C,當有兩個盤子,就將B當作輔助柱。

如圖所示:

事實上,若有n個盤子,則移動完畢所需之次數為2^n - 1,所以當盤數為64時,則所需次數為:264- 1 = 18446744073709551615 為5.05390248594782e+16年,也就是約5000世紀,如果對這數字沒什麼概念,就假設每秒鐘搬一個盤子好了,也要約5850億年左右。 

實現:

//Java程式的實現
import java.io.*;
public class Hanoi {
    public static void main(String args[]) throws IOException {
        int n;
        BufferedReader buf;
        buf = new BufferedReader(new InputStreamReader(System. in ));
        System.out.print("請輸入盤數:");
        n = Integer.parseInt(buf.readLine());
        Hanoi hanoi = new Hanoi();
        hanoi.move(n, 'A', 'B', 'C');
    }
    public void move(int n, char a, char b, char c) {
        if (n == 1) System.out.println("盤 " + n + " 由 " + a + " 移至 " + c);
        else {
            move(n - 1, a, c, b);
            System.out.println("盤 " + n + " 由 " + a + " 移至 " + c);
            move(n - 1, b, a, c);
        }
    }
}


2)費式數列

說明:

Fibonacci為1200年代的歐洲數學家,在他的著作中曾經提到:“若有一隻免子每個月生一隻小免子,一個月後小免子也開始生產。起初只有一隻免子,一個月後就有兩隻免子,二個月後有三隻免子,三個月後有五隻免子(小免子投入生產)......”。

如果不太理解這個例子的話,舉個圖就知道了,注意新生的小免子需一個月成長期才會投入生產,類似的道理也可以用於植物的生長,這就是Fibonacci數列,一般習慣稱之為費氏數列,例如以下:

1、1 、2、3、5、8、13、21、34、55、89......

解法:

依說明,我們可以將費氏數列定義為以下:

fn = fn-1 + fn-2     if n > 2

fn = 1              if n = 0, 1 

實現:

//Java程式的實現:
public class Fibonacci {
    public static void main(String[] args) {
        int[] fib = new int[20];
        fib[0] = 0;
        fib[1] = 1;
        for (int i = 2; i < fib.length; i++) fib[i] = fib[i - 1] + fib[i - 2];
        for (int i = 0; i < fib.length; i++) System.out.print(fib[i] + " ");
        System.out.println();
    }
}


3)巴斯卡(Pascal)三角形

說明:

巴斯卡(Pascal)三角形基本上就是在解 nCr ,因為三角形上的每一個數字各對應一個nCr,其中 n 為 row,而 r 為 column,如下:

0C0

1C0 1C1

2C0 2C1 2C2

3C0 3C1 3C2 3C3

4C0 4C1 4C2 4C3 4C4

對應的資料如下圖所示:

解法:

巴斯卡三角形中的 nCr 可以使用以下這個公式來計算,以避免階乘運算時的數值溢位:

nCr = [(n-r+1)*nCr-1]/r

nC0 = 1 

實現:


//java實現
import java.awt.*;
import javax.swing.*;
public class Pascal extends JFrame {
    public Pascal() {
        setBackground(Color.white);
        setTitle("巴斯卡三角形");
        setSize(520, 350);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(700, 700);
        setVisible(true);
    }
    private long combi(int n, int r) {
        int i;
        long p = 1;
        for (i = 1; i <= r; i++) p = p * (n - i + 1) / i;
        return p;
    }
    public void paint(Graphics g) {
        g.setColor(Color.white);
        g.clearRect(0, 0, getSize().width, getSize().height);
        g.setColor(Color.red);
        final int N = 12;
        int n, r, t;
        for (n = 0; n <= N; n++) {
            for (r = 0; r <= n; r++) g.drawString(" " + combi(n, r), (N - n) * 20 + r * 40, n * 20 + 50);
        }
    }
    public static void main(String args[]) {
        Pascal frm = new Pascal();
    }
}

4)蒙地卡羅法求 PI

說明:

蒙地卡羅為摩洛哥王國之首都,該國位於法國與義大利國境,以賭博聞名。蒙地卡羅的基本原理為以亂數配合面積公式來進行解題,這種以機率來解題的方式帶有賭博的意味,雖然在精確度上有所疑慮,但其解題的思考方向卻是個值得學習的方式。

解法:

蒙地卡羅的解法適用於與面積有關的題目,例如求PI值或橢圓面積,這邊介紹如何求PI值;假設有一個圓半徑為1,所以四分之一圓面積就為PI,而包括此四分之一圓的正方形面積就為1,如下圖所示:

如果隨意的在正方形中投射飛標(點)好了,則這些飛標(點)有些會落於四分之一圓內,假設所投射的飛標(點)有n點,在圓內的飛標(點)有c點,則依比例來算,就會得到上圖中最後的公式。

至於如何判斷所產生的點落於圓內,很簡單,令亂數產生X與Y兩個數值,如果X^2+Y^2等於1就是落在圓內。

實現:

//java程式實現
public class PI {
    public static void main(String[] args) {
        final int N = 50000;
        int sum = 0;
        for (int i = 1; i < N; i++) {
            double x = Math.random();
            double y = Math.random();
            if ((x * x + y * y) < 1) sum++;
        }
        System.out.println("PI = " + (double) 4 * sum / N);
    }
}


5)最大公因數、最小公倍數

說明:

解法:

最大公因數使用輾轉相除法來求,最小公倍數則由這個公式來求:

GCD * LCM = 兩數乘積

實現:

//java程式實現
import java.io.*;
public class GcdLcm {
    public static int gcdOf(int m, int n) {
        int r;
        while (n != 0) {
            r = m % n;
            m = n;
            n = r;
        }
        return m;
    }
    public static int lcmOf(int m, int n) {
        return m * n / gcdOf(m, n);
    }
    public static void main(String[] args) throws IOException {
        BufferedReader ln = new BufferedReader(new InputStreamReader(System. in ));
        System.out.print("請輸入第一個數:");
        int x = Integer.parseInt(ln.readLine());
        System.out.print("請輸入第二個數:");
        int y = Integer.parseInt(ln.readLine());
        System.out.println("GCD of (" + x + "," + y + ")=" + GcdLcm.gcdOf(x, y));
        System.out.println("LCM of (" + x + "," + y + ")=" + GcdLcm.lcmOf(x, y));
    }
}


6)阿姆斯壯數

說明:

在三位的整數中,例如153可以滿足13 + 53 + 33 = 153,這樣的數稱之為Armstrong數,試寫出一程式找出所有的三位數Armstrong數。

解法:

Armstrong數的尋找,其實就是在問如何將一個數字分解為個位數、十位數、百位數......,這隻要使用除法與餘數運算就可以了,例如輸入 input為abc,則:

a = input / 100

b = (input%100) / 10

c = input % 10

實現:

//java程式實現
public class Armstrong {
    public static void main(String[] args) {
        System.out.println("尋找Armstrong數:");
        for (int i = 100; i <= 999; i++) {
            int a = i / 100;
            int b = (i % 100) / 10;
            int c = i % 10;
            if (a * a * a + b * b * b + c * c * c == i) System.out.print(i + " ");
        }
        System.out.println();
    }
}


7)最大訪客數

說明:

現將舉行一個餐會,讓訪客事先填寫到達時間與離開時間,為了掌握座位的數目,必須先估計不同時間的最大訪客數。

解法:

這個題目看似有些複雜,其實相當簡單,單就計算訪客數這個目的,同時考慮同一訪客的來訪時間與離開時間,反而會使程式變得複雜;只要將來訪時間與離開時間分開處理就可以了,假設訪客 i 的來訪時間為x[i],而離開時間為y[i]。

在資料輸入完畢之後,將x[i]與y[i]分別進行排序(由小到大),道理很簡單,只要先計算某時之前總共來訪了多少訪客,然後再減去某時之前的離開訪客,就可以輕易的解出這個問題

實現:

//java實現
import java.io.*;
import java.util.*;
public class MaxVisit {
    public static int maxGuest(int[] x, int[] y, int time) {
        int num = 0;
        for (int i = 0; i < x.length; i++) {
            if (time > x[i]) num++;
            if (time > y[i]) num--;
        }
        return num;
    }
    public static void main(String[] args) throws IOException {
        BufferedReader buf = new BufferedReader(new InputStreamReader(System. in ));
        System.out.println("輸入來訪時間與離開時間(0~24):");
        System.out.println("範例:10 15");
        System.out.println("輸入-1結束");
        java.util.ArrayList list = new ArrayList();
        while (true) {
            System.out.print(">>");
            String input = buf.readLine();
            if (input.equals("-1")) break;
            list.add(input);
        }
        int[] x = new int[list.size()];
        int[] y = new int[list.size()];
        for (int i = 0; i < x.length; i++) {
            String input = (String) list.get(i);
            String[] strs = input.split(" ");
            x[i] = Integer.parseInt(strs[0]);
            y[i] = Integer.parseInt(strs[1]);
        }
        Arrays.sort(x);
        Arrays.sort(y);
        for (int time = 0; time < 25; time++) {
            System.out.println(time + " 時的最大訪客數:" + MaxVisit.maxGuest(x, y, time));
        }
    }
}


8)洗撲克牌(亂數排列)

說明:

洗撲克牌的原理其實與亂數排列是相同的,都是將一組數字(例如1~N)打亂重新排列,只不過洗撲克牌多了一個花色判斷的動作而已。

<