日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java一些必会算法(转自落尘曦的博客:http://blog.csdn.net/qq_23994787。 )

發(fā)布時(shí)間:2023/12/15 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java一些必会算法(转自落尘曦的博客:http://blog.csdn.net/qq_23994787。 ) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

經(jīng)典算法的Java實(shí)現(xiàn)

(1)河內(nèi)塔問(wèn)題: 42

(2)費(fèi)式數(shù)列 43

(3)巴斯卡(Pascal)三角形 44

(4)蒙地卡羅法求 PI 45

(5)最大公因數(shù)、最小公倍數(shù) 46

(6)阿姆斯壯數(shù) 47

(7)最大訪客數(shù) 48

(8)洗撲克牌(亂數(shù)排列) 49

(9)約瑟夫問(wèn)題(Josephus Problem) 50

(10)排列組合 52

(11)得分排行 53

(12)選擇、插入、氣泡排序 55

(13)快速排序(一) 58

(14)快速排序(二) 60

(15)快速排序(三) 61

(16)合并排序 62

(17)基數(shù)排序 63

(18)循序查找法(使用衛(wèi)兵) 65

(19)二分查找法 66

(20)插補(bǔ)查找法 67

(21)費(fèi)式查找法 68

(22)稀疏矩陣 71

(23)多維矩陣轉(zhuǎn)一維矩陣 72

(24)上三角、下三角、對(duì)稱矩陣 73

(25)奇數(shù)魔方陣 75

(26)4N魔方陣 76

(27)2(2n+1)魔方陣 78

?

?

1.大O表示法:粗略的量度方法即算法的速度是如何與數(shù)據(jù)項(xiàng)的個(gè)數(shù)相關(guān)的

?

算法??????????????????????????????????????????????????????????????大O表示法表示的運(yùn)行時(shí)間

線性查找??????????????????????????????????????????????????????????????O(N)

二分查找??????????????????????????????????????????????????????????????O(logN)

無(wú)序數(shù)組的插入????????????????????????????????????????????????????????O(1)

有序數(shù)組的插入????????????????????????????????????????????????????????O(N)

無(wú)序數(shù)組的刪除????????????????????????????????????????????????????????O(N)

有序數(shù)組的刪除????????????????????????????????????????????????????????O(N)

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

?

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("插入排序循環(huán)次數(shù):" + num);

  • ??????? System.out.println("移動(dòng)次數(shù):" + 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("選擇排序循環(huán)次數(shù):" + num);

  • ??????? System.out.println("移動(dòng)次數(shù):" + 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("冒泡排序循環(huán)次數(shù):" + num);

  • ??????? System.out.println("移動(dòng)次數(shù):" + 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.?優(yōu)先級(jí)隊(duì)列

  • 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) {

  • //優(yōu)先級(jí)隊(duì)列的插入不是隊(duì)尾,而是選擇一個(gè)合適的按照某種順序插入的

  • //當(dāng)隊(duì)列長(zhǎng)度為0時(shí),如下

  • //不為0時(shí),將所有比要插入的數(shù)小的數(shù)據(jù)后移,這樣大的數(shù)就在隊(duì)列的頭部了

  • 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() {

  • //移出的是數(shù)組最上端的數(shù),這樣減少數(shù)組元素的移動(dòng)

  • return a[--nItems];

  • }

  • public boolean isEmpty() {

  • return (nItems == 0);

  • }

  • public boolean isFull() {

  • return (nItems == maxSize);

  • }

  • public int size() {

  • return nItems;

  • }

  • }

  • public class duilie { // 隊(duì)列體類

  • 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 { // 隊(duì)列操作類

  • /**

  • ?
  • * @param args

  • ?
  • */

  • private int i = 0; // 隊(duì)列長(zhǎng)

  • private duilie top = new duilie(""); // 隊(duì)列頭

  • private duilie end = new duilie(""); // 隊(duì)列尾

  • public void add(String s) { // 添加隊(duì)列

  • duilie m = new duilie(s);

  • if (i != 0) {

  • m.setS(top.getS());

  • top.setS(m);

  • } else {

  • top.setS(m);

  • end.setS(m);

  • }

  • i++;

  • }


  • ?

    4.?隊(duì)列

    ?

  • public void del() { // 刪除隊(duì)尾

  • if (i == 0) {

  • return;

  • } else if (i == 1) {

  • top.setS(null);

  • end.setS(null);

  • } else {

  • duilie top1 = new duilie(""); // 隊(duì)列底查找用緩存

  • 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;

  • }

  • // 擴(kuò)大數(shù)組

  • 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();

  • }

  • // 進(jìn)棧

  • 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 // 節(jié)點(diǎn)類,單鏈表上的節(jié)點(diǎn)

  • {

  • String data; // 數(shù)據(jù)域,存放String類的數(shù)據(jù)

  • Node next; // 指向下一個(gè)節(jié)點(diǎn)

  • Node(String data) {

  • this.data = data; // 構(gòu)造函數(shù)

  • }

  • String get() {

  • return data; // 返回?cái)?shù)據(jù)

  • }

  • }

  • class MyLinkList // 鏈表類

  • {

  • Node first; // 頭節(jié)點(diǎn)

  • int size; // 鏈表長(zhǎng)度

  • MyLinkList(String arg[]) {

  • // Node first = new Node("head");//生成頭節(jié)點(diǎn)

  • first = new Node("head"); // J.F. 這里不需要定義局部變量 first

  • // 如果定義了局部變量,那成員變量 first 就一直沒(méi)有用上

  • // 所以,它一直為空

  • size = 0;

  • Node p = first;

  • for (int i = 0; i < arg.length; i++) // 將arg數(shù)組中的元素分別放入鏈表中

  • {

  • Node q = new Node(arg[i]);

  • q.next = p.next; // 每一個(gè)節(jié)點(diǎn)存放一個(gè)arg數(shù)組中的元素

  • p.next = q;

  • p = p.next;

  • size++;

  • }

  • }

  • MyLinkList() // 無(wú)參數(shù)構(gòu)造函數(shù)

  • {

  • // Node first = new Node("head");

  • first = new Node("head"); // J.F. 這里犯了和上一個(gè)構(gòu)造方法同樣的錯(cuò)誤

  • size = 0;

  • }

  • int size() // 返回鏈表長(zhǎng)度

  • {

  • return size;

  • }

  • void insert(Node a, int index) // 將節(jié)點(diǎn)a 插入鏈表中的第index個(gè)位置

  • {

  • Node temp = first;

  • for (int i = 0; i < index; i++) {

  • temp = temp.next; // 找到插入節(jié)點(diǎn)的前一節(jié)點(diǎn)

  • }

  • a.next = temp.next; // 插入節(jié)點(diǎn)

  • temp.next = a;

  • size++;

  • }

  • Node del(int index) // 刪除第index個(gè)節(jié)點(diǎn),并返回該值

  • {

  • Node temp = first;

  • for (int i = 0; i < index; i++) {

  • temp = temp.next; // 找到被刪除節(jié)點(diǎn)的前一節(jié)點(diǎn)

  • }

  • Node node = temp.next;

  • temp.next = node.next;

  • size--; // 刪除該節(jié)點(diǎn),鏈表長(zhǎng)度減一

  • return node;

  • }

  • void print() // 在屏幕上輸出該鏈表(這段程序總是出錯(cuò),不知道錯(cuò)在哪里)

  • {

  • Node temp = first;

  • for (int i = 1; i < size; i++) // 將各個(gè)節(jié)點(diǎn)分別在屏幕上輸出

  • {

  • temp = temp.next;

  • System.out.print(temp.get() + "->");

  • }

  • }

  • void reverse() // 倒置該鏈表

  • {

  • for (int i = 0; i < size; i++) {

  • insert(del(size - 1), 0); // 將最后一個(gè)節(jié)點(diǎn)插入到最前

  • // J.F. 最后一個(gè)節(jié)點(diǎn)的 index 應(yīng)該是 size - 1

  • // 因?yàn)榈谝粋€(gè)節(jié)點(diǎn)的 index 是 0

  • }

  • }

  • String get(int index) // 查找第index個(gè)節(jié)點(diǎn),返回其值

  • {

  • if (index >= size) {

  • return null;

  • }

  • Node temp = first;

  • for (int i = 0; i < index; i++) {

  • temp = temp.next; // 找到被查找節(jié)點(diǎn)的前一節(jié)點(diǎn)

  • }

  • return temp.next.get();

  • }

  • }

  • class MyStack // 堆棧類,用單鏈表實(shí)現(xiàn)

  • {

  • MyLinkList tmp;

  • Node temp;

  • MyStack() {

  • // MyLinkList tmp = new MyLinkList();

  • tmp = new MyLinkList(); // J.F. 和 MyLinkList 構(gòu)造方法同樣的錯(cuò)誤

  • }

  • void push(String a) // 壓棧,即往鏈表首部插入一個(gè)節(jié)點(diǎn)

  • {

  • Node temp = new Node(a);

  • tmp.insert(temp, 0);

  • }

  • String pop() // 出棧,將鏈表第一個(gè)節(jié)點(diǎn)刪除

  • {

  • 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 // 測(cè)試程序部分

  • {

  • public static void main(String arg[]) // 程序入口

  • {

  • if ((arg.length == 0) || (arg.length > 10)) System.out.println("長(zhǎng)度超過(guò)限制或者缺少參數(shù)");

  • else {

  • MyLinkList ll = new MyLinkList(arg); // 創(chuàng)建一個(gè)鏈表

  • ll.print(); // 先輸出該鏈表(運(yùn)行到這一步拋出異常)

  • ll.reverse(); // 倒置該鏈表

  • ll.print(); // 再輸出倒置后的鏈表

  • String data[] = new String[10];

  • int i;

  • for (i = 0; i < ll.size(); i++) {

  • data[i] = ll.get(i); // 將鏈表中的數(shù)據(jù)放入數(shù)組

  • }

  • // sort(data);// 按升序排列data中的數(shù)據(jù)(有沒(méi)有現(xiàn)成的排序函數(shù)?)

  • for (i = 0; i < ll.size(); i++) {

  • System.out.print(data[i] + ";"); // 輸出數(shù)組中元素

  • }

  • System.out.println();

  • MyStack s = new MyStack(); // 創(chuàng)建堆棧實(shí)例s

  • for (i = 0; i < ll.size(); i++) {

  • s.push(data[i]); // 將數(shù)組元素壓棧

  • }

  • 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的第一個(gè)條件是沒(méi)有到達(dá)鏈表的尾端,第二個(gè)是按順序找到一個(gè)合適的位置

  • while (current != null && key > current.iData) {

  • previous = current;

  • current = current.next;

  • }

  • // 如果是空表或者要插入的元素最小,則在表頭插入key

  • if (current == first) first = newLink;

  • else previous.next = newLink;

  • newLink.next = current;

  • }

  • /**

  • ?
  • * 刪除表頭的節(jié)點(diǎn)

  • ?
  • *

  • ?
  • * @return 要?jiǎng)h除的節(jié)點(diǎn)

  • ?
  • */

  • 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 {

  • // 雙向鏈表,有兩個(gè)指針,一個(gè)向前,一個(gè)向后

  • 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;

  • }

  • /**

  • ?
  • * 在表頭插入數(shù)據(jù)

  • ?
  • *

  • ?
  • * @param 要插入的節(jié)點(diǎn)的數(shù)據(jù)

  • ?
  • */

  • public void insertFirst(int key) {

  • Link newLink = new Link(key);

  • // 如果開(kāi)始鏈表為空,則插入第一個(gè)數(shù)據(jù)后,last也指向第一個(gè)數(shù)據(jù)

  • if (this.isEmpty()) last = newLink;

  • else { // 表不為空的情況

  • first.previous = newLink;

  • newLink.next = first;

  • }

  • // 無(wú)論怎樣,插入后都的讓first重新指向第一個(gè)節(jié)點(diǎn)

  • first = newLink;

  • }

  • public void insertLast(int key) { // 在尾端插入數(shù)據(jù),同上

  • Link newLink = new Link(key);

  • if (this.isEmpty()) first = newLink;

  • else {

  • last.next = newLink;

  • newLink.previous = last;

  • }

  • last = newLink;

  • }

  • /**

  • ?
  • * 在指定的節(jié)點(diǎn)后插入數(shù)據(jù)

  • ?
  • *

  • ?
  • * @param key

  • ?
  • * 指定的節(jié)點(diǎn)的值

  • ?
  • * @param iData

  • ?
  • * 要插入的數(shù)據(jù)

  • ?
  • * @return 是否插入成功

  • ?
  • */

  • public boolean insertAfter(int key, int iData) {

  • Link newLink = new Link(key);

  • Link current = first;

  • // 從first開(kāi)始遍歷,看能否找到以key為關(guān)鍵字的節(jié)點(diǎn)

  • while (current.iData != key) {

  • current = current.next;

  • // 若能找到就跳出循環(huán),否則返回false,插入失敗

  • if (current == null) return false;

  • }

  • // 如果插入點(diǎn)在last的位置

  • if (current == last) {

  • last = newLink;

  • } else { // 非last位置,交換各個(gè)next和previous的指針

  • newLink.next = current.next;

  • current.next.previous = newLink;

  • }

  • current.next = newLink;

  • newLink.previous = current;

  • return true;

  • }

  • /**

  • ?
  • * 刪除表頭的節(jié)點(diǎn)

  • ?
  • *

  • ?
  • * @return

  • ?
  • */

  • public Link deleteFirst() {

  • Link temp = first;

  • // 如果表中只有一個(gè)元素,刪除后則為空表,所以last=null

  • if (first.next == null) last = null;

  • else

  • // 否則,讓第二個(gè)元素的previous=null

  • first.next.previous = null;

  • // 刪除頭指針,則first指向原來(lái)的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;

  • // 遍歷整個(gè)鏈表查找對(duì)應(yīng)的key,如果查到跳出循環(huán),否則...

  • while (current.iData != key) {

  • current = current.next;

  • // ...否則遍歷到表尾,說(shuō)明不存在此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.?實(shí)現(xiàn)二叉樹(shù)前序遍歷迭代器

    ?

  • class TreeNode這個(gè)類用來(lái)聲明樹(shù)的結(jié)點(diǎn),其中有左子樹(shù)、右子樹(shù)和自身的內(nèi)容。

  • class MyTree這個(gè)類用來(lái)聲明一棵樹(shù),傳入根結(jié)點(diǎn)。這里設(shè)計(jì)的比較簡(jiǎn)單

  • class TreeEum這個(gè)類是樹(shù)的迭代器,通過(guò) MyTree類的方法獲取,這里主要就是設(shè)計(jì)它了。代碼如下:

  • //TreeNode類,使用了泛型,由于比較簡(jiǎn)單,考試.大提示不作解釋

  •    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類,沒(méi)什么功能,傳入根結(jié)點(diǎn)構(gòu)造,getEnumerator()方法獲取迭代器。

  •   

  • class MyTree {

  • TreeNode < String > root;  

  • public MyTree(TreeNode < String > root) {  

  • this.root = root;

  • }  

  • public TreeEnum getEnumerator() {  

  • return new TreeEnum(root);

  • }

  • }

  • // 這個(gè)類為迭代器,有詳細(xì)解釋,相信各位能看懂。在棧中用了兩次泛型。

  •   

  • import java.util.Stack;  

  • public class TreeEnum {  

  • private TreeNode < String > root;  

  • private Stack < TreeNode < String >> store; /* 保存遍歷左子樹(shù)但未遍歷右子樹(shù)的結(jié)點(diǎn) */   

  • 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) {

  • /* 如果當(dāng)前結(jié)點(diǎn)的左子樹(shù)不為空,則遍歷左子樹(shù),并標(biāo)記當(dāng)前結(jié)點(diǎn)未遍歷右子樹(shù) */

  •   

  • if (next.left() != null) {

  • store.push(next);

  • next = next.left();

  • }

  • // 如果當(dāng)前結(jié)點(diǎn)的左子樹(shù)為空,則遍歷右子樹(shù)

  •   

  • else if (next.right() != null) {

  • next = next.right();

  • }

  • /* 如果當(dāng)前結(jié)點(diǎn)為葉子,則找未遍歷右子樹(shù)的結(jié)點(diǎn)并且遍歷它的右子樹(shù) */

  •   

  • else {  

  • if (!store.empty()) /* 判斷是否還有結(jié)點(diǎn)的右子樹(shù)未遍歷 */ {

  • TreeNode < String > tmp = store.pop();

  • /* 如果有未遍歷右子樹(shù)的結(jié)點(diǎn),但它的右子樹(shù)為空,且還有結(jié)點(diǎn)的右子樹(shù)未遍歷, */

  • /* 則一直往上取,直到取到未遍歷右子樹(shù)且右子樹(shù)不為空的結(jié)點(diǎn),遍歷它的右子樹(shù). */

  •   

  • while ((tmp.right() == null) && !store.empty()) {

  • tmp = store.pop();

  • }

  • next = tmp.right();

  • }  

  • else {

  • /* 如果沒(méi)有哪個(gè)結(jié)點(diǎn)右子樹(shù)未遍歷,則表示沒(méi)有下一個(gè)結(jié)點(diǎn)了,設(shè)置next為null */

  • next = null;

  • }

  • }

  • }  

  • return current;

  • }  

  • public boolean hasMoreElement() {  

  • return next != null;

  • }

  • }  下面寫(xiě)個(gè)測(cè)試類,不作解釋,相信大家看得懂  

  • 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();

  • }這個(gè)接口我們有

  • 2個(gè)方法, hasNext()是否還有下一條數(shù)據(jù), next返回具體的 Object這里也就是樹(shù)。我們先不必要忙著做他的實(shí)現(xiàn)類,我們現(xiàn)在要來(lái)做的是這個(gè)容器(不是 JAVA中容器,與 arraylist什么的無(wú)關(guān)),正所謂樹(shù)的容器是什么,是山也!我們想想山應(yīng)該具有什么呢!?首先它要有種植樹(shù)的功能,這里可以看作添加樹(shù)。我們可以想像山的功能是和樹(shù)相互關(guān)聯(lián)的,那么他們之間是什么關(guān)系呢,我們給他們一種聚合的關(guān)系,聚合的關(guān)系大家可以參考 UML圖,我在這里給出它的一種程序表現(xiàn)形式。

  • package TreeIterator;

  • public class Hall {

  • Tree[] tree; // 這里可以看作是聚合關(guān)系

  • private int index; // 指向Tree[]的標(biāo)簽

  • 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類來(lái), Tree[] tree可以看作是山和樹(shù)之間的一種聚合關(guān)系。 add方法就是添加樹(shù)。問(wèn)題來(lái)了,山和樹(shù)有了關(guān)系,那么山和迭代器有什么關(guān)系呢。它們之間肯定有一種關(guān)系。我們有了這個(gè)容器(山),就要把這個(gè)容器來(lái)實(shí)現(xiàn)迭代的方法: hasNext()和 Next().恩這里我們可以看出,山和迭代器之間也是一種關(guān)聯(lián)關(guān)系。我們就把它看成是一種聚合關(guān)系(TIP:聚合關(guān)系一種特殊的關(guān)聯(lián)關(guān)系)。我們可以通過(guò)一個(gè) connectIterator方法來(lái)鏈接山和迭代器,接下來(lái)我們要去做一個(gè)具體的迭代類,這個(gè)具體的類中間有了 hasNext()和 Next()的具體實(shí)現(xiàn)方法

  • ?
  • 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就可以看作是一種關(guān)聯(lián)關(guān)系,我們要把山和迭代器聯(lián)系起來(lái)就通過(guò)構(gòu)造函數(shù)來(lái)實(shí)現(xiàn), hasNext和 next實(shí)現(xiàn)方法就體現(xiàn)出來(lái)了有了山,有了迭代器,可是樹(shù)還沒(méi)有定義,不過(guò)這個(gè)樹(shù)的方法還很好解決!樹(shù)不關(guān)聯(lián)其他的事務(wù),我們可以簡(jiǎn)單的這么寫(xiě):

  • ?
  • package TreeIterator;

  • public class Tree {

  • private String name;

  • public Tree(String name) {

  • this.name = name;

  • }

  • public String getName() {

  • return this.name;

  • }

  • }

  • ?
  • 好了似乎我們整個(gè)工程完工了,我們現(xiàn)在來(lái)模擬一下農(nóng)民老大伯來(lái)種樹(shù)撒肥的過(guò)程;

  • ?
  • package TreeIterator;

  • public class Pren {

  • public Pren() {}

  • public static void main(String[] args) {

  • Hall hall = new Hall(4);

  • hall.add(new Tree("蘋(píng)果樹(shù)"));

  • hall.add(new Tree("梨樹(shù)"));

  • hall.add(new Tree("橘子樹(shù)"));

  • hall.add(new Tree("鳳梨樹(shù)"));

  • for (Iterator i = hall.connectIterator(); i.hasNext();) {

  • String Type = ((Tree)(i.next())).getName();

  • if (Type == "蘋(píng)果樹(shù)") {

  • System.out.println("灑蘋(píng)果樹(shù)的農(nóng)藥,");

  • }

  • if (Type == "梨樹(shù)") {

  • System.out.println("灑梨樹(shù)的農(nóng)藥");

  • }

  • if (Type == "橘子樹(shù)") {

  • System.out.println("灑橘子樹(shù)的農(nóng)藥,灑了也沒(méi)用,還沒(méi)到成熟日,現(xiàn)在沒(méi)結(jié)果實(shí)");

  • }

  • if (Type == "鳳梨樹(shù)") {

  • System.out.println("南風(fēng)天,濕氣大,讓它爛在地里吧");

  • }

  • }

  • }

  • }

  • 種4個(gè)樹(shù),山小而五臟俱全,更像一個(gè)土包,再要有樹(shù)才行啊,所以 4個(gè)樹(shù)的實(shí)例出現(xiàn)。好了接下來(lái)種樹(shù),幾毫秒解決!山了有我們就要把山放到迭代器中間去了。遍歷這個(gè)山(容器)。聯(lián)想我們看看 arrayList中的迭代器模式是怎么實(shí)現(xiàn)的!

  • 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.?歸并排序

  • /**

  • ?
  • * 歸并排序,要求待排序的數(shù)組必須實(shí)現(xiàn)Comparable接口

  • ?
  • */

  • public class MergeSort implements SortStrategy {

  • private Comparable[] bridge;

  • /**

  • ?
  • * 利用歸并排序算法對(duì)數(shù)組obj進(jìn)行排序

  • ?
  • */

  • public void sort(Comparable[] obj) {

  • if (obj == null) {

  • throw new NullPointerException("The param can not be null!");

  • }

  • bridge = new Comparable[obj.length]; // 初始化中間數(shù)組

  • mergeSort(obj, 0, obj.length - 1); // 歸并排序

  • bridge = null;

  • }

  • /**

  • ?
  • * 將下標(biāo)從left到right的數(shù)組進(jìn)行歸并排序

  • ?
  • *

  • ?
  • * @param obj

  • ?
  • * 要排序的數(shù)組的句柄

  • ?
  • * @param left

  • ?
  • * 要排序的數(shù)組的第一個(gè)元素下標(biāo)

  • ?
  • * @param right

  • ?
  • * 要排序的數(shù)組的最后一個(gè)元素的下標(biāo)

  • ?
  • */

  • 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);

  • }

  • }

  • /**

  • ?
  • * 將兩個(gè)對(duì)象數(shù)組進(jìn)行歸并,并使歸并后為升序。歸并前兩個(gè)數(shù)組分別有序

  • ?
  • *

  • ?
  • * @param obj

  • ?
  • * 對(duì)象數(shù)組的句柄

  • ?
  • * @param left

  • ?
  • * 左數(shù)組的第一個(gè)元素的下標(biāo)

  • ?
  • * @param center

  • ?
  • * 左數(shù)組的最后一個(gè)元素的下標(biāo)

  • ?
  • * @param right

  • ?
  • * 右數(shù)組的最后一個(gè)元素的下標(biāo)

  • ?
  • */

  • 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) { // 從兩個(gè)數(shù)組中取出小的放入中間數(shù)組

  • if (obj[left].compareTo(obj[mid]) <= 0) {

  • bridge[third++] = obj[left++];

  • } else bridge[third++] = obj[mid++];

  • }

  • // 剩余部分依次置入中間數(shù)組

  • while (mid <= right) {

  • bridge[third++] = obj[mid++];

  • }

  • while (left <= center) {

  • bridge[third++] = obj[left++];

  • }

  • // 將中間數(shù)組的內(nèi)容拷貝回原數(shù)組

  • copy(obj, tmp, right);

  • }

  • /**

  • ?
  • * 將中間數(shù)組bridge中的內(nèi)容拷貝到原數(shù)組中

  • ?
  • *

  • ?
  • * @param obj

  • ?
  • * 原數(shù)組的句柄

  • ?
  • * @param left

  • ?
  • * 要拷貝的第一個(gè)元素的下標(biāo)

  • ?
  • * @param right

  • ?
  • * 要拷貝的最后一個(gè)元素的下標(biāo)

  • ?
  • */

  • 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) {

  • // 設(shè)置兩個(gè)滑標(biāo)

  • int lowCursor = low + 1;

  • int highCursor = high;

  • // 交換時(shí)的臨時(shí)變量

  • int temp = 0;

  • // 比較樞值,設(shè)為數(shù)組的第一個(gè)值

  • int medi = data[low];

  • while (true) {

  • // 從低端開(kāi)始查找,確定大于數(shù) data[low] 所在的位置

  • while (lowCursor < high && data[lowCursor] < medi) {

  • lowCursor++;

  • }

  • // 從高端開(kāi)始查找,確定小于數(shù) data[low] 所在的位置。這里要使用 >= 判斷確定小于值

  • while (highCursor > low && data[highCursor] >= medi) {

  • highCursor--;

  • }

  • // 兩游標(biāo)位置出現(xiàn)越界,退出循環(huán)

  • if (lowCursor >= highCursor) {

  • break;

  • }

  • // 交換 data[highCursor] 和 data[lowCursor] 位置數(shù)據(jù)

  • temp = data[highCursor];

  • data[highCursor] = data[lowCursor];

  • data[lowCursor] = temp;

  • }

  • // 由 while 循環(huán)退出條件可知:lowCursor > highCursor

  • // 當(dāng)前 lowCursor 指向右側(cè)大于 data[low]的第一個(gè)位置;

  • // 而 highCursor 指向左側(cè)小于 data[low]的第一個(gè)位置,所以需要交換 data[low] 和

  • // data[highCursor]的值

  • data[low] = data[highCursor];

  • data[highCursor] = medi;

  • // 遞歸運(yùn)算左半部分

  • if (low < highCursor) {

  • recQuickSort(data, low, highCursor);

  • }

  • // 遞歸運(yùn)算右半部分

  • 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.?二叉樹(shù)

    ?

  • //******************************************************************************************************//

  • //*****本程序包括簡(jiǎn)單的二叉樹(shù)類的實(shí)現(xiàn)和前序,中序,后序,層次遍歷二叉樹(shù)算法,*******//

  • //******以及確定二叉樹(shù)的高度,制定對(duì)象在樹(shù)中的所處層次以及將樹(shù)中的左右***********//

  • //******孩子節(jié)點(diǎn)對(duì)換位置,返回葉子節(jié)點(diǎn)個(gè)數(shù)刪除葉子節(jié)點(diǎn),并輸出所刪除的葉子節(jié)點(diǎn)**//

  • //*******************************CopyRight By phoenix*******************************************//

  • //************************************Jan 12,2008*************************************************//

  • //****************************************************************************************************//

  • public class BinTree {

  • public final static int MAX = 40;

  • BinTree[] elements = new BinTree[MAX]; // 層次遍歷時(shí)保存各個(gè)節(jié)點(diǎn)

  • int front; // 層次遍歷時(shí)隊(duì)首

  • int rear; // 層次遍歷時(shí)隊(duì)尾

  • private Object data; // 數(shù)據(jù)元數(shù)

  • private BinTree left, right; // 指向左,右孩子結(jié)點(diǎn)的鏈

  • public BinTree() {}

  • public BinTree(Object data) { // 構(gòu)造有值結(jié)點(diǎn)

  • this.data = data;

  • left = right = null;

  • }

  • public BinTree(Object data, BinTree left, BinTree right) { // 構(gòu)造有值結(jié)點(diǎn)

  • this.data = data;

  • this.left = left;

  • this.right = right;

  • }

  • public String toString() {

  • return data.toString();

  • }

  • // 前序遍歷二叉樹(shù)

  • public static void preOrder(BinTree parent) {

  • if (parent == null) return;

  • System.out.print(parent.data + " ");

  • preOrder(parent.left);

  • preOrder(parent.right);

  • }

  • // 中序遍歷二叉樹(shù)

  • public void inOrder(BinTree parent) {

  • if (parent == null) return;

  • inOrder(parent.left);

  • System.out.print(parent.data + " ");

  • inOrder(parent.right);

  • }

  • // 后序遍歷二叉樹(shù)

  • public void postOrder(BinTree parent) {

  • if (parent == null) return;

  • postOrder(parent.left);

  • postOrder(parent.right);

  • System.out.print(parent.data + " ");

  • }

  • // 層次遍歷二叉樹(shù)

  • 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;

  • }

  • }

  • }

  • // 返回樹(shù)的葉節(jié)點(diǎn)個(gè)數(shù)

  • 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());

  • }

  • // 結(jié)果返回樹(shù)的高度

  • 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;

  • }

  • // 如果對(duì)象不在樹(shù)中,結(jié)果返回-1;否則結(jié)果返回該對(duì)象在樹(shù)中所處的層次,規(guī)定根節(jié)點(diǎn)為第一層

  • public int level(Object object) {

  • int levelInTree;

  • if (this == null) return -1;

  • if (object == data) return 1; // 規(guī)定根節(jié)點(diǎn)為第一層

  • 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;

  • }

  • // 將樹(shù)中的每個(gè)節(jié)點(diǎn)的孩子對(duì)換位置

  • public void reflect() {

  • if (this == null) return;

  • if (left != null) left.reflect();

  • if (right != null) right.reflect();

  • BinTree temp = left;

  • left = right;

  • right = temp;

  • }

  • // 將樹(shù)中的所有節(jié)點(diǎn)移走,并輸出移走的節(jié)點(diǎn)

  • public void defoliate() {

  • if (this == null) return;

  • // 若本節(jié)點(diǎn)是葉節(jié)點(diǎn),則將其移走

  • if (left == null && right == null) {

  • System.out.print(this + " ");

  • data = null;

  • return;

  • }

  • // 移走左子樹(shù)若其存在

  • if (left != null) {

  • left.defoliate();

  • left = null;

  • }

  • // 移走本節(jié)點(diǎn),放在中間表示中跟移走...

  • // innerNode += this + " ";

  • data = null;

  • // 移走右子樹(shù)若其存在

  • 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("前序遍歷二叉樹(shù)結(jié)果: ");

  • tree.preOrder(tree);

  • System.out.println();

  • System.out.println("中序遍歷二叉樹(shù)結(jié)果: ");

  • tree.inOrder(tree);

  • System.out.println();

  • System.out.println("后序遍歷二叉樹(shù)結(jié)果: ");

  • tree.postOrder(tree);

  • System.out.println();

  • System.out.println("層次遍歷二叉樹(shù)結(jié)果: ");

  • tree.LayerOrder(tree);

  • System.out.println();

  • System.out.println("F所在的層次: " + tree.level("F"));

  • System.out.println("這棵二叉樹(shù)的高度: " + tree.height());

  • System.out.println("--------------------------------------");

  • tree.reflect();

  • System.out.println("交換每個(gè)節(jié)點(diǎn)的孩子節(jié)點(diǎn)后......");

  • System.out.println("前序遍歷二叉樹(shù)結(jié)果: ");

  • tree.preOrder(tree);

  • System.out.println();

  • System.out.println("中序遍歷二叉樹(shù)結(jié)果: ");

  • tree.inOrder(tree);

  • System.out.println();

  • System.out.println("后序遍歷二叉樹(shù)結(jié)果: ");

  • tree.postOrder(tree);

  • System.out.println();

  • System.out.println("層次遍歷二叉樹(shù)結(jié)果: ");

  • tree.LayerOrder(tree);

  • System.out.println();

  • System.out.println("F所在的層次: " + tree.level("F"));

  • System.out.println("這棵二叉樹(shù)的高度: " + tree.height());

  • }

  • }


  • ?

    ?

    ?

    ?

    ?

    ?

    經(jīng)典算法的Java實(shí)現(xiàn)

    (1)河內(nèi)塔問(wèn)題:

    說(shuō)明:

    河內(nèi)之塔(Towers of Hanoi)是法國(guó)人M.Claus(Lucas)于1883年從泰國(guó)帶至法國(guó)的,河內(nèi)為越戰(zhàn)時(shí)北越的首都,即現(xiàn)在的胡志明市;1883年法國(guó)數(shù)學(xué)家 Edouard Lucas曾提及這個(gè)故事,據(jù)說(shuō)創(chuàng)世紀(jì)時(shí)Benares有一座波羅教塔,是由三支鉆石棒(Pag)所支撐,開(kāi)始時(shí)神在第一根棒上放置64個(gè)由上至下依由小至大排列的金盤(pán)(Disc),并命令僧侶將所有的金盤(pán)從第一根石棒移至第三根石棒,且搬運(yùn)過(guò)程中遵守大盤(pán)子在小盤(pán)子之下的原則,若每日僅搬一個(gè)盤(pán)子,則當(dāng)盤(pán)子全數(shù)搬運(yùn)完畢之時(shí),此塔將毀損,而也就是世界末日來(lái)臨之時(shí)。

    解法:

    如果柱子標(biāo)為ABC,要由A搬至C,在只有一個(gè)盤(pán)子時(shí),就將它直接搬至C,當(dāng)有兩個(gè)盤(pán)子,就將B當(dāng)作輔助柱。

    如圖所示:

    事實(shí)上,若有n個(gè)盤(pán)子,則移動(dòng)完畢所需之次數(shù)為2^n - 1,所以當(dāng)盤(pán)數(shù)為64時(shí),則所需次數(shù)為:264- 1 = 18446744073709551615 為5.05390248594782e+16年,也就是約5000世紀(jì),如果對(duì)這數(shù)字沒(méi)什么概念,就假設(shè)每秒鐘搬一個(gè)盤(pán)子好了,也要約5850億年左右。?

    實(shí)現(xiàn):

  • //Java程序的實(shí)現(xiàn)

  • 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("請(qǐng)輸入盤(pán)數(shù):");

  • 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("盤(pán) " + n + " 由 " + a + " 移至 " + c);

  • else {

  • move(n - 1, a, c, b);

  • System.out.println("盤(pán) " + n + " 由 " + a + " 移至 " + c);

  • move(n - 1, b, a, c);

  • }

  • }

  • }


  • ?

    (2)費(fèi)式數(shù)列

    說(shuō)明:

    Fibonacci為1200年代的歐洲數(shù)學(xué)家,在他的著作中曾經(jīng)提到:“若有一只免子每個(gè)月生一只小免子,一個(gè)月后小免子也開(kāi)始生產(chǎn)。起初只有一只免子,一個(gè)月后就有兩只免子,二個(gè)月后有三只免子,三個(gè)月后有五只免子(小免子投入生產(chǎn))......”。

    如果不太理解這個(gè)例子的話,舉個(gè)圖就知道了,注意新生的小免子需一個(gè)月成長(zhǎng)期才會(huì)投入生產(chǎn),類似的道理也可以用于植物的生長(zhǎng),這就是Fibonacci數(shù)列,一般習(xí)慣稱之為費(fèi)氏數(shù)列,例如以下:

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

    解法:

    依說(shuō)明,我們可以將費(fèi)氏數(shù)列定義為以下:

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

    fn = 1       ???????if n = 0, 1?

    實(shí)現(xiàn):

  • //Java程序的實(shí)現(xiàn):

  • 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)三角形

    說(shuō)明:

    巴斯卡(Pascal)三角形基本上就是在解 nCr ,因?yàn)槿切紊系拿恳粋€(gè)數(shù)字各對(duì)應(yīng)一個(gè)nCr,其中 n 為 row,而 r 為 column,如下:

    0C0

    1C0 1C1

    2C0 2C1 2C2

    3C0 3C1 3C2 3C3

    4C0 4C1 4C2 4C3 4C4

    ?

    對(duì)應(yīng)的數(shù)據(jù)如下圖所示:

    ?

    ?

    解法:

    巴斯卡三角形中的?nCr 可以使用以下這個(gè)公式來(lái)計(jì)算,以避免階乘運(yùn)算時(shí)的數(shù)值溢位:

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

    nC0 = 1?

    ?

    實(shí)現(xiàn):

    ?

    ?

  • //java實(shí)現(xiàn)

  • 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

    說(shuō)明:

    蒙地卡羅為摩洛哥王國(guó)之首都,該國(guó)位于法國(guó)與義大利國(guó)境,以賭博聞名。蒙地卡羅的基本原理為以亂數(shù)配合面積公式來(lái)進(jìn)行解題,這種以機(jī)率來(lái)解題的方式帶有賭博的意味,雖然在精確度上有所疑慮,但其解題的思考方向卻是個(gè)值得學(xué)習(xí)的方式。

    解法:

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

    ?

    ?

    如果隨意的在正方形中投射飛標(biāo)(點(diǎn))好了,則這些飛標(biāo)(點(diǎn))有些會(huì)落于四分之一圓內(nèi),假設(shè)所投射的飛標(biāo)(點(diǎn))有n點(diǎn),在圓內(nèi)的飛標(biāo)(點(diǎn))有c點(diǎn),則依比例來(lái)算,就會(huì)得到上圖中最后的公式。

    至于如何判斷所產(chǎn)生的點(diǎn)落于圓內(nèi),很簡(jiǎn)單,令亂數(shù)產(chǎn)生X與Y兩個(gè)數(shù)值,如果X^2+Y^2等于1就是落在圓內(nèi)。

    ?

    實(shí)現(xiàn):

  • //java程序?qū)崿F(xiàn)

  • 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)最大公因數(shù)、最小公倍數(shù)

    說(shuō)明:

    解法:

    最大公因數(shù)使用輾轉(zhuǎn)相除法來(lái)求,最小公倍數(shù)則由這個(gè)公式來(lái)求:

    GCD * LCM = 兩數(shù)乘積

    實(shí)現(xiàn):

  • //java程序?qū)崿F(xiàn)

  • 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("請(qǐng)輸入第一個(gè)數(shù):");

  • int x = Integer.parseInt(ln.readLine());

  • System.out.print("請(qǐng)輸入第二個(gè)數(shù):");

  • 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)阿姆斯壯數(shù)

    說(shuō)明:

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

    解法:

    Armstrong數(shù)的尋找,其實(shí)就是在問(wèn)如何將一個(gè)數(shù)字分解為個(gè)位數(shù)、十位數(shù)、百位數(shù)......,這只要使用除法與余數(shù)運(yùn)算就可以了,例如輸入 input為abc,則:

    a = input / 100

    b = (input%100) / 10

    c = input % 10

    ?

    實(shí)現(xiàn):

  • //java程序?qū)崿F(xiàn)

  • public class Armstrong {

  • public static void main(String[] args) {

  • System.out.println("尋找Armstrong數(shù):");

  • 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)最大訪客數(shù)

    說(shuō)明:

    現(xiàn)將舉行一個(gè)餐會(huì),讓訪客事先填寫(xiě)到達(dá)時(shí)間與離開(kāi)時(shí)間,為了掌握座位的數(shù)目,必須先估計(jì)不同時(shí)間的最大訪客數(shù)。

    解法:

    這個(gè)題目看似有些復(fù)雜,其實(shí)相當(dāng)簡(jiǎn)單,單就計(jì)算訪客數(shù)這個(gè)目的,同時(shí)考慮同一訪客的來(lái)訪時(shí)間與離開(kāi)時(shí)間,反而會(huì)使程式變得復(fù)雜;只要將來(lái)訪時(shí)間與離開(kāi)時(shí)間分開(kāi)處理就可以了,假設(shè)訪客?i 的來(lái)訪時(shí)間為x[i],而離開(kāi)時(shí)間為y[i]。

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

    實(shí)現(xiàn):

  • //java實(shí)現(xiàn)

  • 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("輸入來(lái)訪時(shí)間與離開(kāi)時(shí)間(0~24):");

  • System.out.println("范例:10 15");

  • System.out.println("輸入-1結(jié)束");

  • 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 + " 時(shí)的最大訪客數(shù):" + MaxVisit.maxGuest(x, y, time));

  • }

  • }

  • }


  • ?

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

    說(shuō)明:

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

    解法:

    初學(xué)者通常會(huì)直接想到,隨機(jī)產(chǎn)生1~N的亂數(shù)并將之存入陣列中,后來(lái)產(chǎn)生的亂數(shù)存入陣列前必須先檢查陣列中是否已有重復(fù)的數(shù)字,如果有這個(gè)數(shù)就不存入,再重新產(chǎn)生下一個(gè)數(shù),運(yùn)氣不好的話,重復(fù)的次數(shù)就會(huì)很多,程式的執(zhí)行速度就很慢了,這不是一個(gè)好方法。

    以1~52的亂數(shù)排列為例好了,可以將陣列先依序由1到52填入,然后使用一個(gè)回圈走訪陣列,并隨機(jī)產(chǎn)生1~52的亂數(shù),將產(chǎn)生的亂數(shù)當(dāng)作索引取出陣列值,并與目前陣列走訪到的值相交換,如此就不用擔(dān)心亂數(shù)重復(fù)的問(wèn)題了,陣列走訪完畢后,所有的數(shù)字也就重新排列了。

    至于如何判斷花色?這只是除法的問(wèn)題而已,取商數(shù)判斷花色,取余數(shù)判斷數(shù)字,您可以直接看程式比較清楚。

    ?

    實(shí)現(xiàn):

  • //java實(shí)現(xiàn)

  • public class ShuffleCard {

  • public static void main(String args[]) {

  • final int N = 52;

  • int[] poker = new int[N + 1];

  • // 初始化陣列

  • for (int i = 1; i <= N; i++) poker[i] = i;

  • // 洗牌

  • for (int i = 1; i <= N; i++) {

  • int j = (int)(Math.random() * N);

  • if (j == 0) j = 1;

  • int tmp = poker[i];

  • poker[i] = poker[j];

  • poker[j] = tmp;

  • }

  • for (int i = 1; i <= N; i++) {

  • // 判斷花色

  • switch ((poker[i] - 1) / 13) {

  • case 0:

  • System.out.print("桃");

  • break;

  • case 1:

  • System.out.print("心");

  • break;

  • case 2:

  • System.out.print("磚");

  • break;

  • case 3:

  • System.out.print("梅");

  • break;

  • }

  • // 撲克牌數(shù)字

  • int remain = poker[i] % 13;

  • switch (remain) {

  • case 0:

  • System.out.print("K ");

  • break;

  • case 12:

  • System.out.print("Q ");

  • break;

  • case 11:

  • System.out.print("J ");

  • break;

  • default:

  • System.out.print(remain + " ");

  • break;

  • }

  • if (i % 13 == 0) System.out.println("");

  • }

  • }

  • }


  • ?

    (9)約瑟夫問(wèn)題(Josephus Problem)

    說(shuō)明:

    據(jù)說(shuō)著名猶太歷史學(xué)家?Josephus有過(guò)以下的故事:在羅馬人占領(lǐng)喬塔帕特后,39 個(gè)猶太人與Josephus及他的朋友躲到一個(gè)洞中,39個(gè)猶太人決定寧愿死也不要被敵人到,于是決定了一個(gè)自殺方式,41個(gè)人排成一個(gè)圓圈,由第1個(gè)人 開(kāi)始報(bào)數(shù),每報(bào)數(shù)到第3人該人就必須自殺,然后再由下一個(gè)重新報(bào)數(shù),直到所有人都自殺身亡為止。

    然而Josephus 和他的朋友并不想遵從,Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個(gè)與第31個(gè)位置,于是逃過(guò)了這場(chǎng)死亡游戲。

    解法:

    約瑟夫問(wèn)題可用代數(shù)分析來(lái)求解,將這個(gè)問(wèn)題擴(kuò)大好了,假設(shè)現(xiàn)在您與m個(gè)朋友不幸參與了這個(gè)游戲,您要如何保護(hù)您與您的朋友?只要畫(huà)兩個(gè)圓圈就可以讓自己與朋友免于死亡游戲,這兩個(gè)圓圈內(nèi)圈是排列順序,而外圈是自殺順序,如下圖所示:

    ?

    使用程式來(lái)求解的話,只要將陣列當(dāng)作環(huán)狀來(lái)處理就可以了,在陣列中由計(jì)數(shù)1開(kāi)始,每找到三個(gè)無(wú)資料區(qū)就填入一個(gè)計(jì)數(shù),直而計(jì)數(shù)達(dá)41為止,然后將陣列由索引1開(kāi)始列出,就可以得知每個(gè)位置的自殺順序,這就是約瑟夫排列,41個(gè)人而報(bào)數(shù)3的約琴夫排列如下所示:

    14 36 1 38 15 2 24 30 3 16 34 4 25 17 5 40 31 6 18 26 7 37 19 8 35 27 9 20 32 10 41 21 11 28 39 12 22 33 13 29 23

    ?

    由上可知,最后一個(gè)自殺的是在第31個(gè)位置,而倒數(shù)第二個(gè)自殺的要排在第16個(gè)位置,之前的人都死光了,所以他們也就不知道約琴夫與他的朋友并沒(méi)有遵守游戲規(guī)則了。

    實(shí)現(xiàn):

  • //java實(shí)現(xiàn)

  • public class Josephus {

  • public static int[] arrayOfJosephus(int number, int per) {

  • int[] man = new int[number];

  • for (int count = 1, i = 0, pos = -1; count <= number; count++) {

  • do {

  • pos = (pos + 1) % number; // 環(huán)狀處理

  • if (man[pos] == 0) i++;

  • if (i == per) { // 報(bào)數(shù)為3了

  • i = 0;

  • break;

  • }

  • } while (true);

  • man[pos] = count;

  • }

  • return man;

  • }

  • public static void main(String[] args) {

  • int[] man = Josephus.arrayOfJosephus(41, 3);

  • int alive = 3;

  • System.out.println("約琴夫排列:");

  • for (int i = 0; i < 41; i++) System.out.print(man[i] + " ");

  • System.out.println("\nL表示3個(gè)存活的人要放的位置:");

  • for (int i = 0; i < 41; i++) {

  • if (man[i] > (41 - alive)) System.out.print("L");

  • else System.out.print("D");

  • if ((i + 1) % 5 == 0) System.out.print(" ");

  • }

  • System.out.println();

  • }

  • }


  • ?

    (10)排列組合

    說(shuō)明:

    將一組數(shù)字、字母或符號(hào)進(jìn)行排列,以得到不同的組合順序,例如1 2 3這三個(gè)數(shù)的排列組合有:1 2 3、1 3 2、2 1 3、2 3 1、3 1 2、3 2 1。

    解法:

    可以使用遞回將問(wèn)題切割為較小的單元進(jìn)行排列組合,例如1 2 3 4的排列可以分為1 [2 3 4]、2 [1 3 4]、3 [1 2 4]、4 [1 2 3]進(jìn)行排列,這邊利用旋轉(zhuǎn)法,先將旋轉(zhuǎn)間隔設(shè)為0,將最右邊的數(shù)字旋轉(zhuǎn)至最左邊,并逐步增加旋轉(zhuǎn)的間隔,例如:

    1 2 3 4 -> 旋轉(zhuǎn)1 -> 繼續(xù)將右邊2 3 4進(jìn)行遞回處理

    2 1 3 4 -> 旋轉(zhuǎn)1 2 變?yōu)?2 1-> 繼續(xù)將右邊1 3 4進(jìn)行遞回處理

    3 1 2 4 -> 旋轉(zhuǎn)1 2 3變?yōu)?3 1 2 -> 繼續(xù)將右邊1 2 4進(jìn)行遞回處理

    4 1 2 3 -> 旋轉(zhuǎn)1 2 3 4變?yōu)? 1 2 3 -> 繼續(xù)將右邊1 2 3進(jìn)行遞回處理

    ?

    實(shí)現(xiàn):

  • //java實(shí)現(xiàn)

  • public class Permutation {

  • public static void perm(int[] num, int i) {

  • if (i < num.length - 1) {

  • for (int j = i; j <= num.length - 1; j++) {

  • int tmp = num[j];

  • // 旋轉(zhuǎn)該區(qū)段最右邊數(shù)字至最左邊

  • for (int k = j; k > i; k--) num[k] = num[k - 1];

  • num[i] = tmp;

  • perm(num, i + 1);

  • // 還原

  • for (int k = i; k < j; k++) num[k] = num[k + 1];

  • num[j] = tmp;

  • }

  • } else {

  • // 顯示此次排列

  • for (int j = 1; j <= num.length - 1; j++) System.out.print(num[j] + " ");

  • System.out.println();

  • }

  • }

  • public static void main(String[] args) {

  • int[] num = new int[4 + 1];

  • for (int i = 1; i <= num.length - 1; i++) num[i] = i;

  • perm(num, 1);

  • }

  • }


  • ?

    (11)得分排行

    說(shuō)明:

    假設(shè)有一教師依學(xué)生座號(hào)輸入考試分?jǐn)?shù),現(xiàn)希望在輸入完畢后自動(dòng)顯示學(xué)生分?jǐn)?shù)的排行,當(dāng)然學(xué)生的分?jǐn)?shù)可能相同。

    ?

    解法:

    這個(gè)問(wèn)題基本上要解不難,只要使用額外的一個(gè)排行陣列走訪分?jǐn)?shù)陣列就可以了,直接使用下面的程式片段作說(shuō)明:

    for(i = 0; i < count; i++) {

    ????juni[i] = 1;

    ????for(j = 0; j < count; j++) {

    ????????if(score[j] > score[i])

    ????????????juni[i]++;

    ???}

    }

    printf("得分\t排行\(zhòng)n");

    for(i = 0; i < count; i++)

    ????printf("%d\t%d\n", score[i], juni[i]);

    上面這個(gè)方法雖然簡(jiǎn)單,但是反覆計(jì)算的次數(shù)是n^2,如果n值變大,那么運(yùn)算的時(shí)間就會(huì)拖長(zhǎng);改變juni陣列的長(zhǎng)度為n+2,并將初始值設(shè)定為0,如下所示:

    接下來(lái)走訪分?jǐn)?shù)陣列,并在分?jǐn)?shù)所對(duì)應(yīng)的排行陣列索引元素上加1,如下所示:

    將排行陣列最右邊的元素設(shè)定為1,然后依序?qū)⒂疫叺脑刂导又磷筮呉粋€(gè)元素,最后排行陣列中的「分?jǐn)?shù)+1」」就是得該分?jǐn)?shù)的排行,如下所示:

    這樣的方式看起來(lái)復(fù)雜,其實(shí)不過(guò)在計(jì)算某分?jǐn)?shù)之前排行的人數(shù),假設(shè)89分之前的排行人數(shù)為x人,則89分自然就是x+1了,這也是為什么排行陣列最右邊要設(shè)定為1的原因;如果89分有y人,則88分自然就是x+y+1,整個(gè)陣列右邊元素向左加的原因正是如此。

    如果分?jǐn)?shù)有負(fù)分的情況,由于C/C++或Java等程式語(yǔ)言無(wú)法處理負(fù)的索引,所以必須加上一個(gè)偏移值,將所有的分?jǐn)?shù)先往右偏移一個(gè)范圍即可,最后顯示的時(shí)候記得減回偏移值就可以了。

    實(shí)現(xiàn):

    ?

  • //

  • import java.io.*;

  • public class ScoreRank {

  • public static void main(String[] args)

  • throws NumberFormatException, IOException {

  • final int MAX = 100;

  • final int MIN = 0;

  • int[] score = new int[MAX + 1];

  • int[] juni = new int[MAX + 2];

  • BufferedReader reader = new BufferedReader(new InputStreamReader(System. in ));

  • int count = 0;

  • do {

  • System.out.print("輸入分?jǐn)?shù),-1結(jié)束:");

  • score[count++] = Integer.parseInt(reader.readLine());

  • } while ((score[count - 1] != -1));

  • count--;

  • for (int i = 0; i < count; i++) juni[score[i]]++;

  • juni[MAX + 1] = 1;

  • for (int i = MAX; i >= MIN; i--) juni[i] = juni[i] + juni[i + 1];

  • System.out.println("得分\t排行");

  • for (int i = 0; i < count; i++) {

  • System.out.println(score[i] + "\t" + juni[score[i] + 1]);

  • }

  • }

  • }


  • ?

    (12)選擇、插入、氣泡排序

    說(shuō)明:

    選擇排序(Selection sort)、插入排序(Insertion sort)與氣泡排序(Bubble sort)這三個(gè)排序方式是初學(xué)排序所必須知道的三個(gè)基本排序方式,它們由于速度不快而不實(shí)用(平均與最快的時(shí)間復(fù)雜度都是O(n2)),然而它們排序的方式確是值得觀察與探討的。

    解法:

    ?

    ?

    ① 選擇排序

    將要排序的對(duì)象分作兩部份,一個(gè)是已排序的,一個(gè)是未排序的,從后端未排序部份選擇一個(gè)最小值,并放入前端已排序部份的最后一個(gè),例如:

    ?

    排序前:70 80 31 37 10 1 48 60 33 80

    ?

    [1] 80 31 37 10 70 48 60 33 80 選出最小值1

    [1 10] 31 37 80 70 48 60 33 80 選出最小值10

    [1 10 31] 37 80 70 48 60 33 80 選出最小值31

    [1 10 31 33] 80 70 48 60 37 80 ......

    [1 10 31 33 37] 70 48 60 80 80 ......

    [1 10 31 33 37 48] 70 60 80 80 ......

    [1 10 31 33 37 48 60] 70 80 80 ......

    [1 10 31 33 37 48 60 70] 80 80 ......

    [1 10 31 33 37 48 60 70 80] 80 ......

    ?

    ② 插入排序

    像是玩樸克一樣,我們將牌分作兩堆,每次從后面一堆的牌抽出最前端的牌,然后插入前面一堆牌的適當(dāng)位置,例如:

    ?

    排序前:92 77 67 8 6 84 55 85 43 67

    ?

    [77 92] 67 8 6 84 55 85 43 67 將77插入92前

    [67 77 92] 8 6 84 55 85 43 67 將67插入77前

    [8 67 77 92] 6 84 55 85 43 67 將8插入67前

    [6 8 67 77 92] 84 55 85 43 67 將6插入8前

    [6 8 67 77 84 92] 55 85 43 67 將84插入92前

    [6 8 55 67 77 84 92] 85 43 67 將55插入67前

    [6 8 55 67 77 84 85 92] 43 67 ......

    [6 8 43 55 67 77 84 85 92] 67 ......

    [6 8 43 55 67 67 77 84 85 92] ......

    ?

    ③ 氣泡排序法

    顧名思義,就是排序時(shí),最大的元素會(huì)如同氣泡一樣移至右端,其利用比較相鄰元素的方法,將大的元素交換至右端,所以大的元素會(huì)不斷的往右移動(dòng),直到適當(dāng)?shù)奈恢脼橹埂?/p>

    ?

    基本的氣泡排序法可以利用旗標(biāo)的方式稍微減少一些比較的時(shí)間,當(dāng)尋訪完陣列后都沒(méi)有發(fā)生任何的交換動(dòng)作,表示排序已經(jīng)完成,而無(wú)需再進(jìn)行之后的回圈比較與交換動(dòng)作,例如:

    ?

    排序前:95 27 90 49 80 58 6 9 18 50

    ?

    27 90 49 80 58 6 9 18 50 [95] 95浮出?

    27 49 80 58 6 9 18 50 [90 95] 90浮出?

    27 49 58 6 9 18 50 [80 90 95] 80浮出?

    27 49 6 9 18 50 [58 80 90 95] ......

    27 6 9 18 49 [50 58 80 90 95] ......

    6 9 18 27 [49 50 58 80 90 95] ......

    6 9 18 [27 49 50 58 80 90 95] 由于接下來(lái)不會(huì)再發(fā)生交換動(dòng)作,排序提早結(jié)束

    ?

    在上面的例子當(dāng)中,還加入了一個(gè)觀念,就是當(dāng)進(jìn)行至i與i+1時(shí)沒(méi)有交換的動(dòng)作,表示接下來(lái)的i+2至n已經(jīng)排序完畢,這也增進(jìn)了氣泡排序的效率。

    ?

    實(shí)現(xiàn):

  • //Java程序?qū)崿F(xiàn)

  • public class BasicSort {

  • public static void selectionSort(int[] number) {

  • for (int i = 0; i < number.length - 1; i++) {》》

  • int m = i;

  • for (int j = i + 1; j < number.length; j++)

  • if (number[j] < number[m]) m = j; === = if (i != m) swap(number, i, m);

  • }

  • }

  • public static void injectionSort(int[] number) {

  • for (int j = 1; j < number.length; j++) {

  • int tmp = number[j];

  • int i = j - 1;

  • while (tmp < number[i]) {

  • number[i + 1] = number[i];

  • i--;

  • if (i == -1) break;

  • }

  • number[i + 1] = tmp;

  • }

  • }

  • public static void bubbleSort(int[] number) {

  • boolean flag = true;

  • for (int i = 0; i < number.length - 1 && flag; i++) {

  • flag = false;

  • for (int j = 0; j < number.length - i - 1; j++) {

  • if (number[j + 1] < number[j]) {

  • swap(number, j + 1, j);

  • flag = true;

  • }

  • }

  • }

  • }

  • private static void swap(int[] number, int i, int j) {

  • int t;

  • t = number[i];

  • number[i] = number[j];

  • number[j] = t;

  • }

  • public static void main(String[] args) {

  • //測(cè)試:

  • int[] a = {

  • 10, 9, 1, 100, 20, 200, 39, 45, 23, 18, 2, 2, 15

  • };

  • //測(cè)試選擇排序:

  • System.out.println("選擇排序前:");

  • for (int x: a) System.out.print(x + " ");

  • System.out.println();

  • int[] b = new int[a.length];

  • b = a;

  • selectionSort(b);

  • System.out.println("選擇排序后:");

  • for (int x: b) System.out.print(x + " ");

  • System.out.println();

  • //測(cè)試插入排序:

  • System.out.println("插入排序前:");

  • for (int x: a) System.out.print(x + " ");

  • System.out.println();

  • int[] c = new int[a.length];

  • c = a;

  • injectionSort(c);

  • System.out.println("插入排序后:");

  • for (int x: c) System.out.print(x + " ");

  • System.out.println();

  • //測(cè)試氣泡排序:

  • System.out.println("氣泡排序前:");

  • for (int x: a) System.out.print(x + " ");

  • System.out.println();

  • int[] d = new int[a.length];

  • d = a;

  • bubbleSort(d);

  • System.out.println("氣泡排序后:");

  • for (int x: d) System.out.print(x + " ");

  • }

  • }


  • ?

    (13)快速排序(一)

    說(shuō)明:

    快速排序法(quick sort)是目前所公認(rèn)最快的排序方法之一(視解題的對(duì)象而定),雖然快速排序法在最差狀況下可以達(dá)O(n2),但是在多數(shù)的情況下,快速排序法的效率表現(xiàn)是相當(dāng)不錯(cuò)的。

    快速排序法的基本精神是在數(shù)列中找出適當(dāng)?shù)妮S心,然后將數(shù)列一分為二,分別對(duì)左邊與右邊數(shù)列進(jìn)行排序,而影響快速排序法效率的正是軸心的選擇。

    這邊所介紹的第一個(gè)快速排序法版本,是在多數(shù)的教科書(shū)上所提及的版本,因?yàn)樗钊菀桌斫?#xff0c;也最符合軸心分割與左右進(jìn)行排序的概念,適合對(duì)初學(xué)者進(jìn)行講解。

    解法:

    這邊所介紹的快速演算如下:將最左邊的數(shù)設(shè)定為軸,并記錄其值為?s

    廻圈處理:

    令索引?i 從數(shù)列左方往右方找,直到找到大于 s 的數(shù)

    令索引?j 從數(shù)列左右方往左方找,直到找到小于 s 的數(shù)

    如果?i >= j,則離開(kāi)回圈

    如果?i < j,則交換索引i與j兩處的值

    將左側(cè)的軸與?j 進(jìn)行交換

    對(duì)軸左邊進(jìn)行遞回

    對(duì)軸右邊進(jìn)行遞回

    ?

    透過(guò)以下演算法,則軸左邊的值都會(huì)小于s,軸右邊的值都會(huì)大于s,如此再對(duì)軸左右兩邊進(jìn)行遞回,就可以對(duì)完成排序的目的,例如下面的實(shí)例,*表示要交換的數(shù),[]表示軸:

    [41] 24 76* 11 45 64 21 69 19 36*

    [41] 24 36 11 45* 64 21 69 19* 76

    [41] 24 36 11 19 64* 21* 69 45 76

    [41] 24 36 11 19 21 64 69 45 76

    21 24 36 11 19 [41] 64 69 45 76

    ?

    在上面的例子中,41左邊的值都比它小,而右邊的值都比它大,如此左右再進(jìn)行遞回至排序完成。

    ?

    實(shí)現(xiàn):

    ?

    ?

  • //java實(shí)現(xiàn)

  • public class QuickSort {

  • public static void sort(int[] number) {

  • sort(number, 0, number.length - 1);

  • }

  • private static void sort(int[] number, int left, int right) {

  • if (left < right) {

  • int s = number[left];

  • int i = left;

  • int j = right + 1;

  • while (true) {

  • // 向右找

  • while (i + 1 < number.length && number[++i] < s);

  • // 向左找

  • while (j - 1 > -1 && number[--j] > s);

  • if (i >= j) break;

  • swap(number, i, j);

  • }

  • number[left] = number[j];

  • number[j] = s;

  • sort(number, left, j - 1);

  • // 對(duì)左邊進(jìn)行遞回

  • sort(number, j + 1, right);

  • // 對(duì)右邊進(jìn)行遞回

  • }

  • }

  • private static void swap(int[] number, int i, int j) {

  • int t;

  • t = number[i];

  • number[i] = number[j];

  • number[j] = t;

  • }

  • }

  • ?

    ?

    (14)快速排序(二)

    說(shuō)明:

    在快速排序法(一)中,每次將最左邊的元素設(shè)為軸,而之前曾經(jīng)說(shuō)過(guò),快速排序法的加速在于軸的選擇,在這個(gè)例子中,只將軸設(shè)定為中間的元素,依這個(gè)元素作基準(zhǔn)進(jìn)行比較,這可以增加快速排序法的效率。

    解法:

    在這個(gè)例子中,取中間的元素s作比較,同樣的先得右找比s大的索引 i,然后找比s小的索引 j,只要兩邊的索引還沒(méi)有交會(huì),就交換 i 與 j 的元素值,這次不用再進(jìn)行軸的交換了,因?yàn)樵趯ふ医粨Q的過(guò)程中,軸位置的元素也會(huì)參與交換的動(dòng)作,例如:

    41 24 76 11 45 64 21 69 19 36

    ?

    首先left為0,right為9,(left+right)/2 = 4(取整數(shù)的商),所以軸為索引4的位置,比較的元素是45,您往右找比45大的,往左找比45小的進(jìn)行交換:

    41 24 76* 11 [45] 64 21 69 19 *36

    41 24 36 11 45* 64 21 69 19* 76

    41 24 36 11 19 64* 21* 69 45 76

    [41 24 36 11 19 21] [64 69 45 76]

    ?

    完成以上之后,再初別對(duì)左邊括號(hào)與右邊括號(hào)的部份進(jìn)行遞回,如此就可以完成排序的目的。

    實(shí)現(xiàn):

    ?

    ?

  • public class QuickSort {

  • public static void sort(int[] number) {

  • sort(number, 0, number.length - 1);

  • }

  • private static void sort(int[] number, int left, int right) {

  • if (left < right) {

  • int s = number[(left + right) / 2];

  • int i = left - 1;

  • int j = right + 1;

  • while (true) {

  • // 向右找

  • while (number[++i] < s);

  • // 向左找

  • while (number[--j] > s);

  • if (i >= j) break;

  • swap(number, i, j);

  • }

  • sort(number, left, i - 1);

  • // 對(duì)左邊進(jìn)行遞回

  • sort(number, j + 1, right);

  • // 對(duì)右邊進(jìn)行遞回

  • }

  • }

  • private static void swap(int[] number, int i, int j) {

  • int t;

  • t = number[i];

  • number[i] = number[j];

  • number[j] = t;

  • }

  • }


  • ?

    ?

    ?

    (15)快速排序(三)

    說(shuō)明:

    之前說(shuō)過(guò)軸的選擇是快速排序法的效率關(guān)鍵之一,在這邊的快速排序法的軸選擇方式更加快了快速排序法的效率,它是來(lái)自演算法名書(shū)?Introduction to Algorithms 之中。

    解法:

    先說(shuō)明這個(gè)快速排序法的概念,它以最右邊的值s作比較的標(biāo)準(zhǔn),將整個(gè)數(shù)列分為三個(gè)部份,一個(gè)是小于s的部份,一個(gè)是大于s的部份,一個(gè)是未處理的部份,如下所示 :

    ?

    ?

    在排序的過(guò)程中,i 與 j 都會(huì)不斷的往右進(jìn)行比較與交換,最后數(shù)列會(huì)變?yōu)橐韵碌臓顟B(tài):

    ?

    ?

    然后將s的值置于中間,接下來(lái)就以相同的步驟會(huì)左右兩邊的數(shù)列進(jìn)行排序的動(dòng)作,如下所示:

    ?

    ?

    整個(gè)演算的過(guò)程,直接摘錄書(shū)中的虛擬碼來(lái)作說(shuō)明:

    ?

    實(shí)現(xiàn):

  • public class QuickSort3 {

  • public static void sort(int[] number) {

  • sort(number, 0, number.length - 1);

  • }

  • private static void sort(int[] number, int left, int right) {

  • if (left < right) {

  • int q = partition(number, left, right);

  • sort(number, left, q - 1);

  • sort(number, q + 1, right);

  • }

  • }

  • private static int partition(int number[], int left, int right) {

  • int s = number[right];

  • int i = left - 1;

  • for (int j = left; j < right; j++) {

  • if (number[j] <= s) {

  • i++;

  • swap(number, i, j);

  • }

  • }

  • swap(number, i + 1, right);

  • return i + 1;

  • }

  • private static void swap(int[] number, int i, int j) {

  • int t;

  • t = number[i];

  • number[i] = number[j];

  • number[j] = t;

  • }

  • }


  • ?

    (16)合并排序

    說(shuō)明:

    之前所介紹的排序法都是在同一個(gè)陣列中的排序,考慮今日有兩筆或兩筆以上的資料,它可能是不同陣列中的資料,或是不同檔案中的資料,如何為它們進(jìn)行排序?

    ?

    解法:

    可以使用合并排序法,合并排序法基本是將兩筆已排序的資料合并并進(jìn)行排序,如果所讀入的資料尚未排序,可以先利用其它的排序方式來(lái)處理這兩筆資料,然后再將排序好的這兩筆資料合并。

    有人問(wèn)道,如果兩筆資料本身就無(wú)排序順序,何不將所有的資料讀入,再一次進(jìn)行排序?排序的精神是盡量利用資料已排序的部份,來(lái)加快排序的效率,小筆資料的排序較為快速,如果小筆資料排序完成之后,再合并處理時(shí),因?yàn)閮晒P資料都有排序了,所有在合并排序時(shí)會(huì)比單純讀入所有的資料再一次排序來(lái)的有效率。

    那么可不可以直接使用合并排序法本身來(lái)處理整個(gè)排序的動(dòng)作?而不動(dòng)用到其它的排序方式?答案是肯定的,只要將所有的數(shù)字不斷的分為兩個(gè)等分,直到最后剩一個(gè)數(shù)字為止,然后再反過(guò)來(lái)不斷的合并,就如下圖所示:

    ?

    不過(guò)基本上分割又會(huì)花去額外的時(shí)間,不如使用其它較好的排序法來(lái)排序小筆資料,再使用合并排序來(lái)的有效率。

    ?

    實(shí)現(xiàn):

  • public class MergeSort {

  • public static int[] sort(int[] number1, int[] number2) {

  • int[] number3 = new int[number1.length + number2.length];

  • int i = 0, j = 0, k = 0;

  • while (i < number1.length && j < number2.length) {

  • if (number1[i] <= number2[j]) number3[k++] = number1[i++];

  • else number3[k++] = number2[j++];

  • }

  • while (i < number1.length) number3[k++] = number1[i++];

  • while (j < number2.length) number3[k++] = number2[j++];

  • return number3;

  • }

  • }


  • ?

    (17)基數(shù)排序

    說(shuō)明:

    在之前所介紹過(guò)的排序方法,都是屬于「比較性」的排序法,也就是每次排序時(shí)?,都是比較整個(gè)鍵值的大小以進(jìn)行排序。

    這邊所要介紹的「基數(shù)排序法」(radix sort)則是屬于「分配式排序」(distribution sort),基數(shù)排序法又稱「桶子法」(bucket sort)或bin sort,顧名思義,它是透過(guò)鍵值的部份資訊,將要排序的元素分配至某些「桶」中,藉以達(dá)到排序的作用,基數(shù)排序法是屬于穩(wěn)定性的排序,其時(shí)間復(fù)雜度為O (nlog(r)m),其中r為所采取的基數(shù),而m為堆數(shù),在某些時(shí)候,基數(shù)排序法的效率高于其它的比較性排序法。

    ?

    解法:

    基數(shù)排序的方式可以采用LSD(Least sgnificant digital)或MSD(Most sgnificant digital),LSD的排序方式由鍵值的最右邊開(kāi)始,而MSD則相反,由鍵值的最左邊開(kāi)始。

    以LSD為例,假設(shè)原來(lái)有一串?dāng)?shù)值如下所示:

    73, 22, 93, 43, 55, 14, 28, 65, 39, 81

    首先根據(jù)個(gè)位數(shù)的數(shù)值,在走訪數(shù)值時(shí)將它們分配至編號(hào)0到9的桶子中:

    0

    1

    2

    3

    4

    5

    6

    7

    8

    9

    ?

    ?

    81

    ?

    ?

    ?

    ?

    ?

    ?

    65

    ?

    ?

    ?

    ?

    ?

    ?

    39

    ?

    ?

    ?

    ?

    ?

    ?

    43

    14

    55

    ?

    ?

    ?

    ?

    28

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    93

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    22

    73

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    接下來(lái)將這些桶子中的數(shù)值重新串接起來(lái),成為以下的數(shù)列:

    81, 22, 73, 93, 43, 14, 55, 65, 28, 39

    接著再進(jìn)行一次分配,這次是根據(jù)十位數(shù)來(lái)分配:

    0

    1

    2

    3

    4

    5

    6

    7

    8

    9

    ?

    ?

    28

    39

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    14

    22

    ?

    ?

    43

    55

    65

    73

    81

    93

    ?

    接下來(lái)將這些桶子中的數(shù)值重新串接起來(lái),成為以下的數(shù)列:

    14, 22, 28, 39, 43, 55, 65, 73, 81, 93

    這時(shí)候整個(gè)數(shù)列已經(jīng)排序完畢;如果排序的對(duì)象有三位數(shù)以上,則持續(xù)進(jìn)行以上的動(dòng)作直至最高位數(shù)為止。

    LSD的基數(shù)排序適用于位數(shù)小的數(shù)列,如果位數(shù)多的話,使用MSD的效率會(huì)比較好,MSD的方式恰與LSD相反,是由高位數(shù)為基底開(kāi)始進(jìn)行分配,其他的演 算方式則都相同。

    ?

    實(shí)現(xiàn):

    ?

    ?

  • public class RadixSort {

  • public static void sort(int[] number, int d) {

  • int k = 0;

  • int n = 1;

  • int[][] temp = new int[number.length][number.length];

  • int[] order = new int[number.length];

  • while (n <= d) {

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

  • int lsd = ((number[i] / n) % 10);

  • temp[lsd][order[lsd]] = number[i];

  • order[lsd]++;

  • }

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

  • if (order[i] != 0)

  • for (int j = 0; j < order[i]; j++) {

  • number[k] = temp[i][j];

  • k++;

  • }

  • order[i] = 0;

  • }

  • n *= 10;

  • k = 0;

  • }

  • }

  • public static void main(String[] args) {

  • int[] data = {

  • 73, 22, 93, 43, 55, 14, 28, 65, 39, 81, 33, 100

  • };

  • RadixSort.sort(data, 100);

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

  • System.out.print(data[i] + " ");

  • }

  • }

  • }

  • ?

    ?

    (18)循序查找法(使用衛(wèi)兵)

    說(shuō)明:

    搜尋的目的,是在「已排序的資料」中尋找指定的資料,而當(dāng)中循序搜尋是最基本的搜尋法,只要從資料開(kāi)頭尋找到最后,看看是否找到資料即可。

    ?

    解法:

    ????初學(xué)者看到循序搜尋,多數(shù)都會(huì)使用以下的方式來(lái)進(jìn)行搜尋:

    while(i < MAX) {

    ????if(number[i] == k) {

    ????????printf("找到指定值");

    ????????break;

    ????}

    ????i++;

    }

    這個(gè)方法基本上沒(méi)有錯(cuò),但是可以加以改善,可以利用設(shè)定衛(wèi)兵的方式,省去if判斷式,衛(wèi)兵通常設(shè)定在數(shù)列最后或是最前方,假設(shè)設(shè)定在列前方好了(索引0的 位置),我們從數(shù)列后方向前找,如果找到指定的資料時(shí),其索引值不是0,表示在數(shù)列走訪完之前就找到了,在程式的撰寫(xiě)上,只要使用一個(gè)while回圈就可 以了。

    實(shí)現(xiàn):

  • public class LinearSearch {

  • public static int search(int[] number, int des) {

  • int[] tmp = new int[number.length + 1];

  • for (int i = 1; i < tmp.length; i++) {

  • tmp[i] = number[i - 1];

  • }

  • tmp[0] = des;

  • int k = tmp[0];

  • int i = number.length;

  • while (tmp[i] != k) i--;

  • return i - 1;

  • }

  • public static void main(String[] args) {

  • int[] number = {

  • 1, 4, 2, 6, 7, 3, 9, 8

  • };

  • QuickSort.sort(number);

  • int find = LinearSearch.search(number, 3);

  • if (find != 0) System.out.println("找到數(shù)值于索引" + find);

  • else System.out.println("找不到數(shù)值");

  • }

  • }


  • ?

    (19)二分查找法

    說(shuō)明:

    如果搜尋的數(shù)列已經(jīng)有排序,應(yīng)該盡量利用它們已排序的特性,以減少搜尋比對(duì)的次數(shù),這是搜尋的基本原則,二分搜尋法是這個(gè)基本原則的代表。

    解法:

    ????在二分搜尋法中,從數(shù)列的中間開(kāi)始搜尋,如果這個(gè)數(shù)小于我們所搜尋的數(shù),由于數(shù)列已排序,則該數(shù)左邊的數(shù)一定都小于要搜尋的對(duì)象,所以無(wú)需浪費(fèi)時(shí)間在左邊的數(shù);如果搜尋的數(shù)大于所搜尋的對(duì)象,則右邊的數(shù)無(wú)需再搜尋,直接搜尋左邊的數(shù)。

    所以在二分搜尋法中,將數(shù)列不斷的分為兩個(gè)部份,每次從分割的部份中取中間數(shù)比對(duì),例如要搜尋92于以下的數(shù)列,首先中間數(shù)索引為(0+9)/2 = 4(索引由0開(kāi)始):

    [3 24 57 57?67?68 83 90 92 95]

    由于67小于92,所以轉(zhuǎn)搜尋右邊的數(shù)列:

    3 24 57 57 67 [68 83?90?92 95]

    由于90小于92,再搜尋右邊的數(shù)列,這次就找到所要的數(shù)了:

    3 24 57 57 67 68 83 90 [92?95]

    ?

    實(shí)現(xiàn):

  • public class BinarySearch {

  • public static int search(int[] number, int des) {

  • int low = 0;

  • int upper = number.length - 1;

  • while (low <= upper) {

  • int mid = (low + upper) / 2;

  • if (number[mid] < des) low = mid + 1;

  • else if (number[mid] > des) upper = mid - 1;

  • else return mid;

  • }

  • return -1;

  • }

  • public static void main(String[] args) {

  • int[] number = {

  • 1, 4, 2, 6, 7, 3, 9, 8

  • };

  • QuickSort.sort(number);

  • int find = BinarySearch.search(number, 3);

  • if (find != -1) System.out.println("找到數(shù)值于索引" + find);

  • else System.out.println("找不到數(shù)值");

  • }

  • }


  • ?

    (20)插補(bǔ)查找法

    說(shuō)明:

    如果卻搜尋的資料分布平均的話,可以使用插補(bǔ)(Interpolation)搜尋法來(lái)進(jìn)行搜尋,在搜尋的對(duì)象大于500時(shí),插補(bǔ)搜尋法會(huì)比 二分搜尋法 來(lái)的快速。

    ?

    解法:

    插補(bǔ)搜尋法是以資料分布的近似直線來(lái)作比例運(yùn)算,以求出中間的索引并進(jìn)行資料比對(duì),如果取出的值小于要尋找的值,則提高下界,如果取出的值大于要尋找的值,則降低下界,如此不斷的減少搜尋的范圍,所以其本原則與二分搜尋法是相同的,至于中間值的尋找是透過(guò)比例運(yùn)算,如下所示,其中K是指定要尋找的對(duì)象, 而m則是可能的索引值:

    ?

    ?

    實(shí)現(xiàn):

  • public class InterpolationSearch {

  • public static int search(int[] number, int des) {

  • int low = 0;

  • int upper = number.length - 1;

  • while (low <= upper) {

  • int mid = (upper - low) * (des - number[low]) / (number[upper] - number[low]) + low;

  • if (mid < low || mid > upper) return -1;

  • if (des < number[mid]) upper = mid - 1;

  • else if (des > number[mid]) low = mid + 1;

  • else return mid;

  • }

  • return -1;

  • }

  • public static void main(String[] args) {

  • int[] number = {

  • 1, 4, 2, 6, 7, 3, 9, 8

  • };

  • QuickSort.sort(number);

  • int find = InterpolationSearch.search(number, 3);

  • if (find != -1) System.out.println("找到數(shù)值于索引" + find);

  • else System.out.println("找不到數(shù)值");

  • }

  • }


  • ?

    ?

    (21)費(fèi)式查找法

    說(shuō)明:

    二分搜尋法每次搜尋時(shí),都會(huì)將搜尋區(qū)間分為一半,所以其搜尋時(shí)間為O(log(2)n),log(2)表示以2為底的log值,這邊要介紹的費(fèi)氏搜尋,其利用費(fèi)氏數(shù)列作為間隔來(lái)搜尋下一個(gè)數(shù),所以區(qū)間收斂的速度更快,搜尋時(shí)間為O(logn)。

    ?

    解法:

    ????費(fèi)氏搜尋使用費(fèi)氏數(shù)列來(lái)決定下一個(gè)數(shù)的搜尋位置,所以必須先制作費(fèi)氏數(shù)列,這在之前有提過(guò);費(fèi)氏搜尋會(huì)先透過(guò)公式計(jì)算求出第一個(gè)要搜尋數(shù)的位置,以及其代表的費(fèi)氏數(shù),以搜尋對(duì)象10個(gè)數(shù)字來(lái)說(shuō),第一個(gè)費(fèi)氏數(shù)經(jīng)計(jì)算后一定是F5,而第一個(gè)要搜尋的位置有兩個(gè)可能,例如若在下面的數(shù)列搜尋的話(為了計(jì)算方便, 通常會(huì)將索引0訂作無(wú)限小的數(shù),而數(shù)列由索引1開(kāi)始):

    ?

    -infin; 1 3 5 7 9 13 15 17 19 20

    ?

    如果要搜尋5的話,則由索引F5 = 5開(kāi)始搜尋,接下來(lái)如果數(shù)列中的數(shù)小于指定搜尋值時(shí),就往左找,大于時(shí)就向右,每次找的間隔是F4、F3、F2來(lái)尋找,當(dāng)費(fèi)氏數(shù)為0時(shí)還沒(méi)找到,就表示尋找失敗,如下所示:

    ?

    ?

    由于第一個(gè)搜尋值索引F5 = 5處的值小于19,所以此時(shí)必須對(duì)齊數(shù)列右方,也就是將第一個(gè)搜尋值的索引改為F5+2 = 7,然后如同上述的方式進(jìn)行搜尋,如下所示:

    ?

    至于第一個(gè)搜尋值是如何找到的?我們可以由以下這個(gè)公式來(lái)求得,其中n為搜尋對(duì)象的個(gè)數(shù):

    Fx + m = n

    Fx <= n

    也就是說(shuō)Fx必須找到不大于n的費(fèi)氏數(shù),以10個(gè)搜尋對(duì)象來(lái)說(shuō):

    Fx + m = 10

    ????取Fx?= 8, m = 2,所以我們可以對(duì)照費(fèi)氏數(shù)列得x = 6,然而第一個(gè)數(shù)的可能位置之一并不是F6,而是第x-1的費(fèi)氏數(shù),也就是F5?= 5。

    如果數(shù)列number在索引5處的值小于指定的搜尋值,則第一個(gè)搜尋位置就是索引5的位置,如果大于指定的搜尋值,則第一個(gè)搜尋位置必須加上m,也就是F5?+ m = 5 + 2 = 7,也就是索引7的位置,其實(shí)加上m的原因,是為了要讓下一個(gè)搜尋值剛好是數(shù)列的最后一個(gè)位置。

    費(fèi)氏搜尋看來(lái)難懂,但只要掌握Fx?+ m = n這個(gè)公式,自己找?guī)讉€(gè)實(shí)例算一次,很容易就可以理解;費(fèi)氏搜尋除了收斂快速之外,由于其本身只會(huì)使用到加法與減法,在運(yùn)算上也可以加快。

    ?

    實(shí)現(xiàn):

    ?

  • public class FibonacciSearch {

  • public static int search(int[] number, int des) {

  • int[] fib = createFibonacci(number.length);

  • int x = findX(fib, number.length + 1, des);

  • int m = number.length - fib[x];

  • x--;

  • int i = x;

  • if (number[i] < des) i += m;

  • while (fib[x] > 0) {

  • if (number[i] < des) i += fib[--x];

  • else if (number[i] > des) i -= fib[--x];

  • else return i;

  • }

  • return -1;

  • }

  • private static int[] createFibonacci(int max) {

  • int[] fib = new int[max];

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

  • fib[i] = Integer.MIN_VALUE;

  • }

  • fib[0] = 0;

  • fib[1] = 1;

  • for (int i = 2; i < max; i++) fib[i] = fib[i - 1] + fib[i - 2];

  • return fib;

  • }

  • private static int findX(int[] fib, int n, int des) {

  • int i = 0;

  • while (fib[i] <= n) i++;

  • i--;

  • return i;

  • }

  • public static void main(String[] args) {

  • int[] number = {

  • 1, 4, 2, 6, 7, 3, 9, 8

  • };

  • QuickSort.sort(number);

  • int find = FibonacciSearch.search(number, 3);

  • if (find != -1) System.out.println("找到數(shù)值于索引" + find);

  • else System.out.println("找不到數(shù)值");

  • }

  • }


  • ?

    ?

    ?

    (22)稀疏矩陣

    說(shuō)明:

    ????如果在矩陣中,多數(shù)的元素并沒(méi)有資料,稱此矩陣為稀疏矩陣(sparse matrix),由于矩陣在程式中常使用二維陣列表示,二維陣列的大小與使用的記憶體空間成正比,如果多數(shù)的元素沒(méi)有資料,則會(huì)造成記憶體空間的浪費(fèi),為 此,必須設(shè)計(jì)稀疏矩陣的陣列儲(chǔ)存方式,利用較少的記憶體空間儲(chǔ)存完整的矩陣資訊。

    ?

    解法:

    在這邊所介紹的方法較為簡(jiǎn)單,陣列只儲(chǔ)存矩陣的行數(shù)、列數(shù)與有資料的索引位置及其值,在需要使用矩陣資料時(shí),再透過(guò)程式運(yùn)算加以還原,例如若矩陣資料如下,其中0表示矩陣中該位置沒(méi)有資料:

    0 0 0 0 0 0

    0 3 0 0 0 0

    0 0 0 6 0 0

    0 0 9 0 0 0

    0 0 0 0 12 0

    這個(gè)矩陣是5X6矩陣,非零元素有4個(gè),您要使用的陣列第一列記錄其列數(shù)、行數(shù)與非零元素個(gè)數(shù):

    5 6 4

    陣列的第二列起,記錄其位置的列索引、行索引與儲(chǔ)存值:

    1 1 3

    2 3 6

    3 2 9

    4 4 12

    所以原本要用30個(gè)元素儲(chǔ)存的矩陣資訊,現(xiàn)在只使用了15個(gè)元素來(lái)儲(chǔ)存,節(jié)省了不少記憶體的使用。

    ?

    實(shí)現(xiàn):

    ?

  • public class SparseMatrix {

  • public static int[][] restore(int[][] sparse) {

  • int row = sparse[0][0];

  • int column = sparse[0][1];

  • int[][] array = new int[row][column];

  • int k = 1;

  • for (int i = 0; i < row; i++) {

  • for (int j = 0; j < column; j++) {

  • if (k <= sparse[0][2] && i == sparse[k][0] && j == sparse[k][1]) {

  • array[i][j] = sparse[k][2];

  • k++;

  • } else array[i][j] = 0;

  • }

  • }

  • return array;

  • }

  • public static void main(String[] args) {

  • int[][] sparse = {

  • {

  • 5, 6, 4

  • }, {

  • 1, 1, 3

  • }, {

  • 2, 3, 6

  • }, {

  • 3, 2, 9

  • }, {

  • 4, 4, 12

  • }

  • };

  • int[][] array = SparseMatrix.restore(sparse);

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

  • for (int j = 0; j < array[i].length; j++) {

  • System.out.print(array[i][j] + " ");

  • }

  • System.out.println();

  • }

  • }

  • }


  • ?

    ?

    ?

    (23)多維矩陣轉(zhuǎn)一維矩陣

    說(shuō)明:

    ????有的時(shí)候,為了運(yùn)算方便或資料儲(chǔ)存的空間問(wèn)題,使用一維陣列會(huì)比二維或多維陣列來(lái)得方便,例如上三角矩陣、下三角矩陣或?qū)蔷仃?#xff0c;使用一維陣列會(huì)比使用二維陣列來(lái)得節(jié)省空間。

    解法:

    以二維陣列轉(zhuǎn)一維陣列為例,索引值由0開(kāi)始,在由二維陣列轉(zhuǎn)一維陣列時(shí),我們有兩種方式:「以列(Row)為主」或「以行(Column)為主」。由于 C/C++、Java等的記憶體配置方式都是以列為主,所以您可能會(huì)比較熟悉前者(Fortran的記憶體配置方式是以行為主)。

    以列為主的二維陣列要轉(zhuǎn)為一維陣列時(shí),是將二維陣列由上往下一列一列讀入一維陣列,此時(shí)索引的對(duì)應(yīng)公式如下所示,其中row與column是二維陣列索引,loc表示對(duì)應(yīng)的一維陣列索引:

    loc = column + row*行數(shù)

    以行為主的二維陣列要轉(zhuǎn)為一維陣列時(shí),是將二維陣列由左往右一行一行讀入一維陣列,此時(shí)索引的對(duì)應(yīng)公式如下所示:

    loc = row + column*列數(shù)

    公式的推導(dǎo)您畫(huà)圖看看就知道了,如果是三維陣列,則公式如下所示,其中i(個(gè)數(shù)u1)、j(個(gè)數(shù)u2)、k(個(gè)數(shù)u3)分別表示三維陣列的三個(gè)索引:

    以列為主:loc = i*u2*u3 + j*u3 + k

    以行為主:loc = k*u1*u2 + j*u1 + i

    ????更高維度的可以自行依此類推,但通常更高維度的建議使用其它資料結(jié)構(gòu)(例如物件包裝)會(huì)比較具體,也不易搞錯(cuò)。

    ?

    實(shí)現(xiàn):

    ??

  • public class TwoDimArray {

  • public static int[] toOneDimByRow(int[][] array) {

  • int[] arr = new int[array.length * array[0].length];

  • for (int row = 0; row < array.length; row++) {

  • for (int column = 0; column < array[0].length; column++) {

  • int i = column + row * array[0].length;

  • arr[i] = array[row][column];

  • }

  • }

  • return arr;

  • }

  • public static int[] toOneDimByColumn(int[][] array) {

  • int[] arr = new int[array.length * array[0].length];

  • for (int row = 0; row < array.length; row++) {

  • for (int column = 0; column < array[0].length; column++) {

  • int i = i = row + column * array.length;

  • arr[i] = array[row][column];

  • }

  • }

  • return arr;

  • }

  • }


  • ?

    ?

    (24)上三角、下三角、對(duì)稱矩陣

    說(shuō)明:

    ????上三角矩陣是矩陣在對(duì)角線以下的元素均為0,即Aij?= 0,i > j,例如:

    1 ?2 ?3 ??4 ??5

    0 ?6 ?7 ??8 ??9

    0 ?0 ?10 ??11 ?12

    0 ?0 ?0 ??13 ?14

    0 ?0 ?0 ??0 ?15

    下三角矩陣是矩陣在對(duì)角線以上的元素均為0,即Aij?= 0,i < j,例如:

    ?1 ?0 ?0 ?0 ?0

    ?2 ?6 ?0 ?0 ?0

    ?3 ?7 ?10 0 ?0

    ?4 ?8 ?11 13 0

    ?5 ?9 ?12 14 15

    對(duì)稱矩陣是矩陣元素對(duì)稱于對(duì)角線,例如:

    ?1 ?2 ?3 ?4 ?5

    ?2 ?6 ?7 ?8 ?9

    ?3 ?7 ?10 11 12

    ?4 ?8 ?11 13 14

    ?5 ?9 ?12 14 15

    上三角或下三角矩陣也有大部份的元素不儲(chǔ)存值(為0),我們可以將它們使用一維陣列來(lái)儲(chǔ)存以節(jié)省儲(chǔ)存空間,而對(duì)稱矩陣因?yàn)閷?duì)稱于對(duì)角線,所以可以視為上三角或下三角矩陣來(lái)儲(chǔ)存。

    解法:

    假設(shè)矩陣為nxn,為了計(jì)算方便,我們讓陣列索引由1開(kāi)始,上三角矩陣化為一維陣列,若以列為主,其公式為:loc = n*(i-1) - i*(i-1)/2 + j

    化為以行為主,其公式為:loc = j*(j-1)/2 + i

    下三角矩陣化為一維陣列,若以列為主,其公式為:loc = i*(i-1)/2 + j

    若以行為主,其公式為:loc = n*(j-1) - j*(j-1)/2 + i

    實(shí)現(xiàn):

    ?

  • public class TriangleArray {

  • private int[] arr;

  • private int length;

  • public TriangleArray(int[][] array) {

  • length = array.length;

  • arr = new int[length * (1 + length) / 2];

  • int loc = 0;

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

  • for (int j = 0; j < length; j++) {

  • if (array[i][j] != 0) arr[loc++] = array[i][j];

  • }

  • }

  • }

  • public int getValue(int i, int j) {

  • int loc = length * i - i * (i + 1) / 2 + j;

  • return arr[loc];

  • }

  • public static void main(String[] args) {

  • int[][] array = {

  • {

  • 1, 2, 3, 4, 5

  • }, {

  • 0, 6, 7, 8, 9

  • }, {

  • 0, 0, 10, 11, 12

  • }, {

  • 0, 0, 0, 13, 14

  • }, {

  • 0, 0, 0, 0, 15

  • }

  • };

  • TriangleArray triangleArray = new TriangleArray(array);

  • System.out.print(triangleArray.getValue(2, 2));

  • }

  • }


  • ?

    ?

    (25)奇數(shù)魔方陣

    說(shuō)明:

    ????將1到n(為奇數(shù))的數(shù)字排列在nxn的方陣上,且各行、各列與各對(duì)角線的和必須相同,如下所示:

    ?

    ?

    解法:

    ????填魔術(shù)方陣的方法以奇數(shù)最為簡(jiǎn)單,第一個(gè)數(shù)字放在第一行第一列的正中央,然后向右(左)上填,如果右(左)上已有數(shù)字,則向下填,如下圖所示:

    ?

    一般程式語(yǔ)言的陣列索引多由0開(kāi)始,為了計(jì)算方便,我們利用索引1到n的部份,而在計(jì)算是向右(左)上或向下時(shí),我們可以將索引值除以n值,如果得到余數(shù)為1就向下,否則就往右(左)上,原理很簡(jiǎn)單,看看是不是已經(jīng)在同一列上繞一圈就對(duì)了。

    ?

    實(shí)現(xiàn):

    ??

  • public class Matrix {

  • public static int[][] magicOdd(int n) {

  • int[][] square = new int[n + 1][n + 1];

  • int i = 0;

  • int j = (n + 1) / 2;

  • for (int key = 1; key <= n * n; key++) {

  • if ((key % n) == 1) i++;

  • else {

  • i--;

  • j++;

  • }

  • if (i == 0) i = n;

  • if (j > n) j = 1;

  • square[i][j] = key;

  • }

  • int[][] matrix = new int[n][n];

  • for (int k = 0; k < matrix.length; k++) {

  • for (int l = 0; l < matrix[0].length; l++) {

  • matrix[k][l] = square[k + 1][l + 1];

  • }

  • }

  • return matrix;

  • }

  • public static void main(String[] args) {

  • int[][] magic = Matrix.magicOdd(5);

  • for (int k = 0; k < magic.length; k++) {

  • for (int l = 0; l < magic[0].length; l++) {

  • System.out.print(magic[k][l] + " ");

  • }

  • System.out.println();

  • }

  • }

  • }


  • ?

    ?

    (26)4N魔方陣

    說(shuō)明:

    ????與?奇數(shù)魔術(shù)方陣?相同,在于求各行、各列與各對(duì)角線的和相等,而這次方陣的維度是4的倍數(shù)。

    解法:

    ????先來(lái)看看4X4方陣的解法:

    ?

    簡(jiǎn)單的說(shuō),就是一個(gè)從左上由1依序開(kāi)始填,但遇對(duì)角線不填,另一個(gè)由左上由16開(kāi)始填,但只填在對(duì)角線,再將兩個(gè)合起來(lái)就是解答了;如果N大于2,則以 4X4為單位畫(huà)對(duì)角線:

    ?

    至于對(duì)角線的位置該如何判斷,有兩個(gè)公式,有興趣的可以畫(huà)圖印證看看,如下所示:

    左上至右下:j % 4 == i % 4

    右上至左下:(j % 4 + i % 4) == 1

    實(shí)現(xiàn):

    ?

  • public class Matrix2 {

  • public static int[][] magicFourN(int n) {

  • int[][] square = new int[n + 1][n + 1];

  • for (int j = 1; j <= n; j++) {

  • for (int i = 1; i <= n; i++) {

  • if (j % 4 == i % 4 || (j % 4 + i % 4) == 1) square[i][j] = (n + 1 - i) * n - j + 1;

  • else square[i][j] = (i - 1) * n + j;

  • }

  • }

  • int[][] matrix = new int[n][n];

  • for (int k = 0; k < matrix.length; k++) {

  • for (int l = 0; l < matrix[0].length; l++) {

  • matrix[k][l] = square[k + 1][l + 1];

  • }

  • }

  • return matrix;

  • }

  • public static void main(String[] args) {

  • int[][] magic = Matrix2.magicFourN(8);

  • for (int k = 0; k < magic.length; k++) {

  • for (int l = 0; l < magic[0].length; l++) {

  • System.out.print(magic[k][l] + " ");

  • }

  • System.out.println();

  • }

  • }

  • }


  • ?

    ?

    ?

    (27)2(2n+1)魔方陣

    說(shuō)明:

    ????方陣的維度整體來(lái)看是偶數(shù),但是其實(shí)是一個(gè)奇數(shù)乘以一個(gè)偶數(shù),例如6X6,其中6=2X3,我們也稱這種方陣與單偶數(shù)方陣。

    解法:

    ????如果您會(huì)解奇數(shù)魔術(shù)方陣,要解這種方陣也就不難理解,首先我們令n=2(2m+1),并將整個(gè)方陣看作是數(shù)個(gè)奇數(shù)方陣的組合,如下所示:

    ?

    首先依序?qū)、B、C、D四個(gè)位置,依奇數(shù)方陣的規(guī)則填入數(shù)字,填完之后,方陣中各行的和就相同了,但列與對(duì)角線則否,此時(shí)必須在A-D與C- B之間,作一些對(duì)應(yīng)的調(diào)換,規(guī)則如下:

    將A中每一列(中間列除外)的頭m個(gè)元素,與D中對(duì)應(yīng)位置的元素調(diào)換。

    將A的中央列、中央那一格向左取m格,并與D中對(duì)應(yīng)位置對(duì)調(diào)

    將C中每一列的倒數(shù)m-1個(gè)元素,與B中對(duì)應(yīng)的元素對(duì)調(diào)

    舉個(gè)實(shí)例來(lái)說(shuō),如何填6X6方陣,我們首先將之分解為奇數(shù)方陣,并填入數(shù)字,如下所示:

    ?

    接下來(lái)進(jìn)行互換的動(dòng)作,互換的元素以不同顏色標(biāo)示,如下:

    ?

    ?

    實(shí)現(xiàn):

    ???

    ?

  • public class Matrix3 {

  • public static int[][] magic22mp1(int n) {

  • int[][] square = new int[n][n];

  • magic_o(square, n / 2);

  • exchange(square, n);

  • return square;

  • }

  • private static void magic_o(int[][] square, int n) {

  • int row = 0;

  • int column = n / 2;

  • for (int count = 1; count <= n * n; count++) {

  • square[row][column] = count;

  • // 填A(yù)

  • square[row + n][column + n] = count + n * n;

  • // 填B

  • square[row][column + n] = count + 2 * n * n;

  • // 填C

  • square[row + n][column] = count + 3 * n * n;

  • // 填D

  • if (count % n == 0) row++;

  • else {

  • row = (row == 0) ? n - 1 : row - 1;

  • column = (column == n - 1) ? 0 : column + 1;

  • }

  • }

  • }

  • private static void exchange(int[][] x, int n) {

  • int i, j;

  • int m = n / 4;

  • int m1 = m - 1;

  • for (i = 0; i < n / 2; i++) {

  • if (i != m) {

  • for (j = 0; j < m; j++)

  • // 處理規(guī)則 1

  • swap(x, i, j, n / 2 + i, j);

  • for (j = 0; j < m1; j++)

  • // 處理規(guī)則 2

  • swap(x, i, n - 1 - j, n / 2 + i, n - 1 - j);

  • } else {

  • // 處理規(guī)則 3

  • for (j = 1; j <= m; j++) swap(x, m, j, n / 2 + m, j);

  • for (j = 0; j < m1; j++) swap(x, m, n - 1 - j, n / 2 + m, n - 1 - j);

  • }

  • }

  • }

  • private static void swap(int[][] number, int i, int j, int k, int l) {

  • int t;

  • t = number[i][j];

  • number[i][j] = number[k][l];

  • number[k][l] = t;

  • }

  • public static void main(String[] args) {

  • int[][] magic = Matrix3.magic22mp1(6);

  • for (int k = 0; k < magic.length; k++) {

  • for (int l = 0; l < magic[0].length; l++) {

  • System.out.print(magic[k][l] + " ");

  • }

  • System.out.println();

  • }

  • }

  • ?
  • 總結(jié)

    以上是生活随笔為你收集整理的java一些必会算法(转自落尘曦的博客:http://blog.csdn.net/qq_23994787。 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。