数据结构与算法(JAVA篇)一

  1. 递归算法
    1. /** 
    2.  * 
    3.  * @author SunnyMoon 
    4.  */  
    5.   
    6.   
    7. /** 
    8.  * 概念介绍: 
    9.  * 递归是一种方法(函数)调用自已编程技术。 
    10.  * 递归就是程序设计中的数学归纳法。 
    11.  * 例如:tri(n)=1            if n=1 
    12.  *     tri(n)=n+tri(n-1)    if n>1 
    13.  * 可能while循环方法执行的速度比递归方法快,但是为什么采用递归呢。 
    14.  * 采用递归,是因为它从概念上简化了问题,而不是因为它提高效率。 
    15.  */  
    16.   
    17. import java.io.BufferedReader;  
    18. import java.io.IOException;  
    19. import java.io.InputStreamReader;  
    20.   
    21.   
    22. public class Recursion {//求三角数字的递归算法:1,3,6,10,15,21, ......  
    23.   
    24.     static int theNumber;  
    25.   
    26.     public static void main(String[] args) throws IOException {  
    27.         System.out.print("Enter a number: ");  
    28.         theNumber = getInt();  
    29.         //使用递归时调用,默认  
    30.         int theAnswer = triangle(theNumber);  
    31.         //使用非递归时调用  
    32.         //int theAnswer=triangle2(theNumber);  
    33.         System.out.println("Result: " + theAnswer);  
    34.     }  
    35.   
    36.     public static int triangle(int n) {//递归方法,循环调用  
    37.         if (n == 1) {  
    38.             return 1;  
    39.         } else {  
    40.             return (n + triangle(n - 1));  
    41.         }  
    42.     }  
    43.   
    44.     public static int triangle2(int n) {//非递归方法  
    45.         int total = 0;  
    46.         while (n > 0) {  
    47.             total = total + n--;  
    48.         }  
    49.         return total;  
    50.     }  
    51.   
    52.     public static String getString() throws IOException {  
    53.         InputStreamReader isr = new InputStreamReader(System.in);  
    54.         BufferedReader br = new BufferedReader(isr);  
    55.         String s = br.readLine();  
    56.         return s;  
    57.     }  
    58.   
    59.     public static int getInt() throws IOException {  
    60.         String s = getString();  
    61.         return Integer.parseInt(s);  
    62.     }  
    63. }  
    64.   
    65. /** 
    66.  * 运行结果: 
    67.  * Enter a number:  
    68.  * 3 
    69.  * Result: 6 
    70.  */  
    71.   
    72. /** 
    73.  * 总结: 
    74.  * 使用非递归的方式更简洁,更易懂,运行效率更高,为什么还要用递归的算法呢。 
    75.  * 递归使规模逐渐降低的方式解决问题,以这种统一的方式解决足够复杂的问题。 
    76.  */ 
    1. /** 
    2.  * 概念介绍: 
    3.  * 
    4.  * 树:树由边连接的节点构成。 
    5.  * 多路树:节点可以多于两个。 
    6.  * 路径:顺着连接点的边从一个节点到另一个节点,所以过的节点顺序排列就称做路径。 
    7.  * 根:树的顶端节点称为根。 
    8.  * 父节点:每个节点都有一条边向上连接到另一个节点,这个节点就称为父节点。 
    9.  * 子节点:每个节点都可能有一条或多条边向下连接其它节点,下面这些节点就称为子节点。 
    10.  * 叶节点:没有子节点的节点为叶子节点或叶节点。 
    11.  * 子树:每个节点都可以作为子树的根,它和它所有的子节点都包含在子树中。 
    12.  * 访问:当程序控制流程到达某个节点时,就称为“访问”这个节点。 
    13.  * 遍历:遍历树意味着要遵循某种特定的顺序访问树中所有的节点。 
    14.  * 层:一个节点的层数是指从根开始到这个节点有多少“代”。一般根为第0层。 
    15.  * 关键字:对象中通常会有一个数据域被指定为关键字,通常使用这个关键字进行查询等操作。 
    16.  * 二叉树:如果树中每个节点最多只能有两个子节点,这样的特殊的树就是二叉树。 
    17.  * 二叉搜索树:二叉树的一个节点的左子节点的关键字值小于这个节点,右子节点的关键字值大 
    18.  *            于或等于这个父节点。 
    19.  * 平衡树与非平衡树:左子节点与左子节点对称的树为平衡树,否则就是非平衡树。 
    20.  * 完全二叉树:二叉树的最后一层都是叶子结点,其它各层都有左右子树,也叫满二叉树。 
    21.  * 
    22.  * 为什么用二叉树:1.二叉树结合了另外两种数据结构的优点:一种是有序数组,另一种是链表。 
    23.  *                在树中查找数据的速度和在有序数组中查找的速度一样快,同时插入的速度 
    24.  *                和删除的速度和链表的速度一样。 
    25.  *                2.在有序数组中插入数据项太慢:用二分查找法可以在有序数据中快速的查找 
    26.  *                特定的值,查找所需时间复杂度为O(logN)。然而插入和删除是非常低效的。 
    27.  *                3.在链表中查找太慢:链表的插入和删除操作都很快,时间复杂度是O(1)。 
    28.  *                然而查找数据项是非常低效的。 
    29.  * 二叉树的效率:时间复杂度为O(logN)。树对所有的数据存储操作都很高效。 
    30.  * 
    31.  * 程序介绍:对树的一些常用操作进行了封装,包括查询,插入,删除,遍历二叉树(中序,后序,前序) 
    32.  *          以及以树的方式显示二对树的各个结点。 
    33.  * 
    34.  */  
    35. /** 
    36.  * 
    37.  * @author SunnyMoon 
    38.  */  
    39.   
    40. import java.io.BufferedReader;  
    41. import java.io.IOException;  
    42. import java.io.InputStreamReader;  
    43.   
    44. /** 
    45.  * 定义树的结点类 
    46.  */  
    47. class Node {  
    48.   
    49.     public int iData;//关键字  
    50.     public double dData;//数据项  
    51.     public Node leftChild;//左子树  
    52.     public Node rightChild;//右子树  
    53.   
    54.     public void displayNode() {//输出结点内容  
    55.         System.out.print("【");  
    56.         System.out.print("关键字: "+iData);  
    57.         System.out.print(",");  
    58.         System.out.print("值:"+dData);  
    59.         System.out.print("】");  
    60.     }  
    61. }  
    62.   
    63. /** 
    64.  * 定义二叉树类 
    65.  */  
    66. class Tree {  
    67.   
    68.     private Node root;  
    69.   
    70.     public Tree() {  
    71.         root = null;  
    72.     }  
    73.   
    74.     /** 
    75.      * 查找 
    76.      * @param key 
    77.      * @return 
    78.      */  
    79.     public Node find(int key) {  
    80.         Node current = root;  
    81.         while (current.iData != key) {  
    82.             if (key < current.iData) {  
    83.                 current = current.leftChild;  
    84.             } else {  
    85.                 current = current.rightChild;  
    86.             }  
    87.             if (current == null) {  
    88.                 return null;  
    89.             }  
    90.         }  
    91.         return current;  
    92.     }  
    93. /** 
    94.  * 插入 
    95.  * @param id 
    96.  * @param dd 
    97.  */  
    98.     public void insert(int id, double dd) {  
    99.         Node newNode = new Node();  
    100.         newNode.iData = id;  
    101.         newNode.dData = dd;  
    102.         if (root == null) {  
    103.             root = newNode;  
    104.         } else {  
    105.             Node current = root;  
    106.             Node parent;  
    107.             while (true) {  
    108.                 parent = current;  
    109.                 if (id < current.iData) {  
    110.                     current = current.leftChild;  
    111.                     if (current == null) {  
    112.                         parent.leftChild = newNode;  
    113.                         return;  
    114.                     }  
    115.                 } else {  
    116.                     current = current.rightChild;  
    117.                     if (current == null) {  
    118.                         parent.rightChild = newNode;  
    119.                         return;  
    120.                     }  
    121.                 }  
    122.             }  
    123.         }  
    124.     }  
    125.   
    126.     /** 
    127.      * 删除 
    128.      * @param key 
    129.      * @return 
    130.      */  
    131.     public boolean delete(int key) {  
    132.         Node current = root;  
    133.         Node parent = root;  
    134.         boolean isLeftChild = true;  
    135.   
    136.         while (current.iData != key) {  
    137.             parent = current;  
    138.             if (key < current.iData) {  
    139.                 isLeftChild = true;  
    140.                 current = current.leftChild;  
    141.             } else {  
    142.                 isLeftChild = false;  
    143.                 current = current.rightChild;  
    144.             }  
    145.             if (current == null) {  
    146.                 return false;  
    147.             }  
    148.         }  
    149.         if (current.leftChild == null && current.rightChild == null) {  
    150.             if (current == root) {  
    151.                 root = null;  
    152.             } else if (isLeftChild) {  
    153.                 parent.leftChild = null;  
    154.             } else {  
    155.                 parent.rightChild = null;  
    156.             }  
    157.         } else if (current.rightChild == null) {  
    158.             if (current == root) {  
    159.                 root = current.leftChild;  
    160.   
    161.             } else if (isLeftChild) {  
    162.                 parent.leftChild = current.leftChild;  
    163.             } else {  
    164.                 parent.rightChild = current.leftChild;  
    165.             }  
    166.         } else if (current.leftChild == null) {  
    167.             if (current == root) {  
    168.                 root = current.rightChild;  
    169.             } else if (isLeftChild) {  
    170.                 parent.leftChild = current.rightChild;  
    171.             } else {  
    172.                 parent.rightChild = current.rightChild;  
    173.             }  
    174.         } else {  
    175.             Node successor = getSuccessor(current);  
    176.             if (current == root) {  
    177.                 root = successor;  
    178.             } else if (isLeftChild) {  
    179.                 parent.leftChild = successor;  
    180.             } else {  
    181.                 parent.rightChild = successor;  
    182.             }  
    183.             successor.leftChild = current.leftChild;  
    184.         }  
    185.         return true;  
    186.     }  
    187. /** 
    188.  * 遍历二叉树 
    189.  * @param traverseType 
    190.  */  
    191.     public void traverse(int traverseType) {  
    192.         switch (traverseType) {  
    193.             case 1:  
    194.                 System.out.print("\n" + "前序遍历(Preorder traversal): ");  
    195.                 preOrder(root);  
    196.                 break;  
    197.             case 2:  
    198.                 System.out.print("\n" + "中序遍历(Inorder traversal): ");  
    199.                 inOrder(root);  
    200.                 break;  
    201.             case 3:  
    202.                 System.out.print("\n" + "后序遍历(Postorder traversal): ");  
    203.                 postOrder(root);  
    204.                 break;  
    205.         }  
    206.         System.out.println();  
    207.     }  
    208. /** 
    209.  * 定义定位到后序结点方法 
    210.  * @param delNode 
    211.  * @return 
    212.  */  
    213.     private Node getSuccessor(Node delNode) {  
    214.         Node successorParent = delNode;  
    215.         Node successor = delNode;  
    216.         Node current = delNode.rightChild;  
    217.         while (current != null) {  
    218.             successorParent = successor;  
    219.             successor = current;  
    220.             current = current.leftChild;  
    221.         }  
    222.         if (successor != delNode.rightChild) {  
    223.             successorParent.leftChild = successor.rightChild;  
    224.             successor.rightChild = delNode.rightChild;  
    225.         }  
    226.         return successor;  
    227.     }  
    228. /** 
    229.  * 前序遍历 
    230.  * @param localRoot 
    231.  */  
    232.     private void preOrder(Node localRoot) {  
    233.         if (localRoot != null) {  
    234.             System.out.print(localRoot.iData + " ");  
    235.             preOrder(localRoot.leftChild);  
    236.             preOrder(localRoot.rightChild);  
    237.         }  
    238.     }  
    239. /** 
    240.  * 中序遍历 
    241.  * @param localRoot 
    242.  */  
    243.     private void inOrder(Node localRoot) {  
    244.         if (localRoot != null) {  
    245.             inOrder(localRoot.leftChild);  
    246.             System.out.print(localRoot.iData + " ");  
    247.             inOrder(localRoot.rightChild);  
    248.         }  
    249.     }  
    250. /** 
    251.  * 后序遍历 
    252.  * @param localRoot 
    253.  */  
    254.     private void postOrder(Node localRoot) {  
    255.         if (localRoot != null) {  
    256.             postOrder(localRoot.leftChild);  
    257.             postOrder(localRoot.rightChild);  
    258.             System.out.print(localRoot.iData + " ");  
    259.         }  
    260.     }  
    261. /** 
    262.  * 把关键字按树型输出 
    263.  * ‘--’表示树中这个位置的结点不存在。 
    264.  */  
    265.     public void displayTree() {  
    266.         Stack globalStack = new Stack(1000);  
    267.         globalStack.push(root);  
    268.         int nBlanks = 32;  
    269.         boolean isRowEmpty = false;  
    270.         System.out.println(  
    271.                 "-----------------------------------------------------------------------");  
    272.         while (isRowEmpty == false) {  
    273.             Stack localStack = new Stack(1000);  
    274.             isRowEmpty = true;  
    275.   
    276.             for (int j = 0; j < nBlanks; j++) {  
    277.                 System.out.print(" ");  
    278.             }  
    279.             while (globalStack.isEmpty() == false) {  
    280.                 Node temp = (Node) globalStack.pop();  
    281.                 if (temp != null) {  
    282.                     System.out.print(temp.iData);  
    283.                     localStack.push(temp.leftChild);  
    284.                     localStack.push(temp.rightChild);  
    285.   
    286.                     if (temp.leftChild != null || temp.rightChild != null) {  
    287.                         isRowEmpty = false;  
    288.                     }  
    289.                 } else {  
    290.                     System.out.print("..");  
    291.                     localStack.push(null);  
    292.                     localStack.push(null);  
    293.                 }  
    294.                 for (int j = 0; j < nBlanks * 2 - 2; j++) {  
    295.                     System.out.print(" ");  
    296.                 }  
    297.             }  
    298.             System.out.println();  
    299.             nBlanks /= 2;  
    300.             while (localStack.isEmpty() == false) {  
    301.                 globalStack.push(localStack.pop());  
    302.             }  
    303.         }  
    304.         System.out.println(  
    305.                 "-----------------------------------------------------------------------");  
    306.     }  
    307. }  
    308.   
    309. /** 
    310.  * 使用的栈 
    311.  * @author Administrator 
    312.  */  
    313. class Stack {  
    314.   
    315.     private int maxSize;  
    316.     private Object[] stackArray;  
    317.     private int top;  
    318.   
    319.     public Stack(int s) {  
    320.         maxSize = s;  
    321.         stackArray = new Object[maxSize];  
    322.         top = -1;  
    323.     }  
    324.   
    325.     public void push(Object p) {  
    326.         stackArray[++top] = p;  
    327.     }  
    328.   
    329.     public Object pop() {  
    330.         return stackArray[top--];  
    331.     }  
    332.   
    333.     public Object peek() {  
    334.         return stackArray[top];  
    335.     }  
    336.   
    337.     boolean isEmpty() {  
    338.         if (top == -1) {  
    339.             return true;  
    340.         } else {  
    341.             return false;  
    342.         }  
    343.     }  
    344. }  
    345. /** 
    346.  * 主方法 
    347.  * @author Administrator 
    348.  */  
    349. class TreeAaa {  
    350.   
    351.     public static void main(String[] args) throws IOException {  
    352.         int value;  
    353.         Tree theTree = new Tree();  
    354.         theTree.insert(121.5);  
    355.         theTree.insert(152.4);  
    356.         theTree.insert(225.6);  
    357.         theTree.insert(337.1);  
    358.         theTree.insert(553.3);  
    359.         theTree.insert(268.7);  
    360.         theTree.insert(172.3);  
    361.         theTree.insert(86.9);  
    362.         theTree.insert(68.4);  
    363.         theTree.insert(147.0);  
    364.         theTree.insert(231.8);  
    365.         theTree.insert(382.9);  
    366.   
    367.         while (true) {  
    368.             System.out.print("输入想执行的操作的英文首字母:");  
    369.             System.out.print("插入(Insert), 查找(Find), 删除(Delete), 遍历(Traverse): ");  
    370.             int choice = getChar();  
    371.             switch (choice) {  
    372.                 case 's':  
    373.                     theTree.displayTree();  
    374.                     break;  
    375.                 case 'i':  
    376.                     System.out.print("输入想要插入的值: ");  
    377.                     value = getInt();  
    378.                     theTree.insert(value, value + 0.9);  
    379.                     break;  
    380.                 case 'f':  
    381.                     System.out.print(("输入想要查找的关键字: "));  
    382.                     value = getInt();  
    383.                     Node found = theTree.find(value);  
    384.                     if (found != null) {  
    385.                         System.out.print("成功查找: ");  
    386.                         found.displayNode();  
    387.                         System.out.print("\n");  
    388.                     } else {  
    389.                         System.out.print("不存在所查询关键字");  
    390.                     }  
    391.                     System.out.print("输入的关键字:" + value + "\n");  
    392.                     break;  
    393.                 case 'd':  
    394.                     System.out.print("输入想要删除的关键字: ");  
    395.                     value = getInt();  
    396.                     boolean didDelete = theTree.delete(value);  
    397.                     if (didDelete) {  
    398.                         System.out.print("删除的值:" + value + "\n");  
    399.                     } else {  
    400.                         System.out.print("不能执行删除操作");  
    401.                     }  
    402.                     System.out.println(value);  
    403.                     //System.out.print(value + "\n");  
    404.                     break;  
    405.                 case 't':  
    406.                     System.out.print("输入遍历类型 1, 2 或 3:");  
    407.                     value = getInt();  
    408.                     theTree.traverse(value);  
    409.                     break;  
    410.                 default:  
    411.                     System.out.println("非法输入");  
    412.             }  
    413.         }  
    414.     }  
    415.   
    416.     public static String getString() throws IOException {  
    417.         InputStreamReader isr = new InputStreamReader(System.in);  
    418.         BufferedReader br = new BufferedReader(isr);  
    419.         String s = br.readLine();  
    420.         return s;  
    421.     }  
    422.   
    423.     public static char getChar() throws IOException {  
    424.         String s = getString();  
    425.         return s.charAt(0);  
    426.     }  
    427.   
    428.     public static int getInt() throws IOException {  
    429.         String s = getString();  
    430.         return Integer.parseInt(s);  
    431.     }  
    432.   /** 
    433.     * 运行结果: 
    434.     * 输入想执行的操作的英文首字母:插入(Insert), 查找(Find), 删除(Delete), 遍历(Traverse): s 
    435.     *----------------------------------------------------------------------- 
    436.     *                                12 
    437.     *                8                              15 
    438.     *        6              ..              14              22 
    439.     *    ..      ..      ..      ..      ..      ..      17      33 
    440.     *  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  26  55 
    441.     * ........................................................23..38.. 
    442.     *----------------------------------------------------------------------- 
    443.     *输入想执行的操作的英文首字母:插入(Insert), 查找(Find), 删除(Delete), 遍历(Traverse): i 
    444.     *输入想要插入的值: 3 
    445.     *输入想执行的操作的英文首字母:插入(Insert), 查找(Find), 删除(Delete), 遍历(Traverse): f 
    446.     *输入想要查找的关键字: 14 
    447.     *成功查找: {14,7.0} 
    448.     *输入的关键字:14 
    449.     *输入想执行的操作的英文首字母:插入(Insert), 查找(Find), 删除(Delete), 遍历(Traverse): 
    450.     */  
    451.  /** 
    452.   * 总结: 
    453.   * 树结合了数组和链表的优点,是一种非常高效的数据结构。 
    454.   */ 
  2. 快速排序/** 

    1. /** 
    2.  * 
    3.  * @author SunnyMoon 
    4.  */  
    5. ////////////////////////////////////////////////////////////////////////////////  
    6. /******************************************************************************* 
    7.  * 概念介绍: 
    8.  * ***************************************************************************** 
    9.  *  
    10.  * 简单排序: 
    11.  * 包括冒泡排序,选择排序和插入排序,是一些容易实现的,但速度比较慢的排序算法。 
    12.  *  
    13.  * 高级排序: 
    14.  * 快速排序,希尔排序和快速排序比简单排序快很多。本节主要介绍快速排序。 
    15.  *  
    16.  * 归并排序: 
    17.  * 在递归算法中已经介绍过,它需要的容易是原始空间的两倍,是一个严重的缺点。 
    18.  *  
    19.  * 希尔排序: 
    20.  * 不需要大量的辅助空间,和归并排序一样容易实现。希尔排序是基于插入排序的一种算法, 
    21.  * 在此算法基础之上增加了一个新的特性,提高了效率。 
    22.  *  
    23.  * 快速排序: 
    24.  * 不需要大量辅助空间,并且是通用排序算法中最快的排序算法,是基于划分的思想。 
    25.  * 快速排序算法本质上是通过把一个数组递归的划分为两个子数组。 
    26.  * 递归的基本步骤: 
    27.  * 1. 把数组划分成以一个元素为枢纽的左右两个子数组。 
    28.  * 2. 调用自身的左边和右边以步骤1递归。 
    29.  * 快速排序法的核心就是递归调用划分算法,直到基值的情况,这时数组就为有序的。 
    30.  * 快速排序的复杂度为: 
    31.  * O(N*logN) 
    32.  *  
    33.  * 影响效率的最大障碍: 
    34.  * 对枢纽数据的选择是影响排序的效率。例如本例子选择枢纽数据为数组的最后一个元素, 
    35.  * 这么选择只是为方便,然而却造成了特殊情况时效率极度下降,降到O(n2)。这种特情况就是当数据为逆序的时候。 
    36.  * 如果改变特殊情况给快速排序带来的致命影响呢,这将在下一专题中详细介绍。 
    37.  */  
    38. ////////////////////////////////////////////////////////////////////////////////  
    39. /** 
    40.  * 定义一个数组类,封装了对自身数据的排序。 
    41.  */  
    42. class ArrayIns {  
    43.   
    44.     private long[] theArray;//定义数组  
    45.     private int nElems;//数组中的元素个数  
    46.   
    47.     /** 
    48.      * 初始化 
    49.      * @param max 
    50.      */  
    51.     public ArrayIns(int max) {  
    52.         theArray = new long[max];  
    53.         nElems = 0;  
    54.     }  
    55.   
    56.     /** 
    57.      * 为数组赋值 
    58.      * @param value 
    59.      */  
    60.     public void insert(long value) {  
    61.         theArray[nElems] = value;  
    62.         nElems++;  
    63.     }  
    64.   
    65.     /** 
    66.      * 显示数组元素 
    67.      */  
    68.     public void display() {  
    69.         System.out.print("A=");  
    70.         for (int j = 0; j < nElems; j++) {  
    71.             System.out.print(theArray[j] + " ");  
    72.         }  
    73.         System.out.println("");  
    74.     }  
    75.   
    76.     /** 
    77.      * 快速排序主方法 
    78.      */  
    79.     public void quickSort(){  
    80.         recQuickSort(0, nElems-1);  
    81.     }  
    82.     /** 
    83.      * 快速排序需递归调用的方法 
    84.      * @param left 
    85.      * @param right 
    86.      */  
    87.     public void recQuickSort(int left, int right) {  
    88.         if (right - left <= 0) {  
    89.             return;  
    90.         } else {  
    91.             long pivot = theArray[right];  
    92.               
    93.             int partition = partitionIt(left, right, pivot);  
    94.             recQuickSort(left, partition - 1);  
    95.             recQuickSort(partition + 1, right);  
    96.         }  
    97.     }  
    98.   
    99.     /** 
    100.      * 快速排序划分的核心方法 
    101.      * @param left 
    102.      * @param right 
    103.      * @param pivot 
    104.      * @return 
    105.      */  
    106.     public int partitionIt(int left, int right, long pivot) {  
    107.         int leftPtr = left-1;  
    108.         int rightPtr = right;  
    109.         while (true) {  
    110.             while (theArray[++leftPtr] < pivot)  
    111.                 ;  
    112.             while (rightPtr > 0 && theArray[--rightPtr] > pivot)  
    113.                 ;  
    114.             if (leftPtr >= rightPtr) {  
    115.                 break;  
    116.             } else {  
    117.                 swap(leftPtr, rightPtr);  
    118.             }  
    119.         }  
    120.         swap(leftPtr,right);  
    121.         return leftPtr;  
    122.     }  
    123.   
    124.     /** 
    125.      * 交换数据中两个位置的数据 
    126.      * @param dex1 
    127.      * @param dex2 
    128.      */  
    129.     public void swap(int dex1, int dex2) {  
    130.         long temp = theArray[dex1];  
    131.         theArray[dex1] = theArray[dex2];  
    132.         theArray[dex2] = temp;  
    133.     }  
    134. }  
    135. /** 
    136.  * 执行算法的主类 
    137.  */  
    138. public class QuickSort1 {  
    139.   
    140.     public static void main(String[] args) {  
    141.         int maxSize = 16;  
    142.         ArrayIns arr = new ArrayIns(maxSize);  
    143.   
    144.         for (int j = 0; j < maxSize; j++) {  
    145.             long n = (int) (java.lang.Math.random()*99);  
    146.             arr.insert(n);  
    147.         }  
    148.         System.out.println("显示排序前数据");  
    149.         arr.display();  
    150.         arr.quickSort();  
    151.         System.out.println("显示排序后数据");  
    152.         arr.display();  
    153.     }  
    154. }  
    155. /** 
    156.  *  
    157.  * 显示排序前数据: 
    158.  * A=9 14 33 27 66 89 53 32 72 14 46 33 13 79 28 26   
    159.  * 显示排序后数据:  
    160.  * A=9 13 14 14 26 27 28 32 33 33 46 53 66 72 79 89  
    161.  */  
    162.   
    163. /** 
    164.  * 总结: 
    165.  * 快速排序是常用排序中效率最高的一种排序方式。 
    166.  * 但在应用中的一此特殊情况影响他的效率,这不是算法本身的问题,而是如果实现的问题。 
    167.  * 已经有很好的实现方式改变一些特殊情况性能下降的问题。 
    168.  */ 
          1.  * 
          2.  * @author SunnyMoon 
          3.  */  
          4. ////////////////////////////////////////////////////////////////////////////////  
          5. /******************************************************************************* 
          6.  * 概念介绍: 
          7.  * ***************************************************************************** 
          8.  * 
          9.  * 影响效率的最大障碍: 
          10.  * 对枢纽数据的选择是影响排序的效率。上一篇文章选择枢纽数据为数组的最后一个元素, 
          11.  * 这么选择只是为方便,然而却造成了特殊情况时效率极度下降,降到O(n2)。这种特情况就是当数据为逆序的时候。 
          12.  * 如果改变特殊情况给快速排序带来的致命影响呢,这将在这一专题中简要介绍。 
          13.  * 
          14.  * 三数据项取中划分: 
          15.  * 目前已经有很多选择更好的枢纽的方法,选择任意一个数据项作为枢纽是一种简单的方法,便是 
          16.  * 正如前文看到的那样,在特殊情况下性能很低。从理论上讲实际使数组中值数据是最理想的枢纽 
          17.  * 选择,是效率最高的方式,但实际上这个过程比排序本身需要更长的时间,因此这是不可行的。 
          18.  * 一种折衷的方法,选择数组里的第一个,最后一个以及中间位置的数据中选择一个中间值,并设 
          19.  * 置此数据项为枢纽,这种选择枢纽的方式为三数据项选中。 
          20.  * 查找三个数据项的中值数据项比查找所有数据项中值快很多,在大多数通常情况下这种方法是又 
          21.  * 快又有效的方法。但是有很特殊的数据排列命名三数据项先中的方法也很低效。 
          22.  * 
          23. //////////////////////////////////////////////////////////////////////////////// 
          24. /** 
          25.  * 定义一个数组类,封装了对自身数据的排序。 
          26.  */  
          27. class ArrayIns {  
          28.   
          29.     private long[] theArray;  
          30.     private int nElems;  
          31.   
          32.     public ArrayIns(int max) {  
          33.         theArray = new long[max];  
          34.         nElems = 0;  
          35.     }  
          36.   
          37.     public void insert(long value) {  
          38.         theArray[nElems] = value;  
          39.         nElems++;  
          40.     }  
          41.   
          42.     public void display() {  
          43.         System.out.print("A=");  
          44.         for (int j = 0; j < nElems; j++) {  
          45.             System.out.print(theArray[j] + " ");  
          46.         }  
          47.         System.out.println("");  
          48.     }  
          49. /** 
          50.  * 快速排序主方法 
          51.  */  
          52.     public void quickSort() {  
          53.         recQuickSort(0, nElems - 1);  
          54.     }  
          55.   
          56. /** 
          57.  * 递归调用快速的排序核心方法 
          58.  * @param left 
          59.  * @param right 
          60.  */  
          61.     public void recQuickSort(int left, int right) {  
          62.         int size = right-left + 1;  
          63.         if (size <= 3) {  
          64.             manualSort(left, right);  
          65.         } else {  
          66.             long median = medianOf3(left, right);//三数取中值  
          67.             int partition=partitionIt(left,right,median);//三数据取中值作为枢纽进行划分  
          68.             recQuickSort(left, partition - 1);//递归排序数组左子元素  
          69.             recQuickSort(partition + 1,right);//递归排序数据左子元素  
          70.         }  
          71.     }  
          72.   
          73. /** 
          74.  * 三数据选中 
          75.  * @param left 
          76.  * @param right 
          77.  * @return 
          78.  */  
          79.     public long medianOf3(int left, int right) {  
          80.         int center = (left + right) / 2;  
          81.   
          82.         if (theArray[left] > theArray[center]) {  
          83.             swap(left, center);  
          84.         }  
          85.         if (theArray[left] > theArray[right]) {  
          86.             swap(left, right);  
          87.         }  
          88.         if (theArray[center] > theArray[right]) {  
          89.             swap(center, right);  
          90.         }  
          91.         swap(center, right - 1);  
          92.         return theArray[right - 1];  
          93.     }  
          94.       
          95. /** 
          96.  * 交换数据 
          97.  * @param dex1 
          98.  * @param dex2 
          99.  */  
          100.     public void swap(int dex1, int dex2) {  
          101.         long temp = theArray[dex1];  
          102.         theArray[dex1] = theArray[dex2];  
          103.         theArray[dex2] = temp;  
          104.     }  
          105.       
          106. /** 
          107.  * 根据三数据选中进行划分 
          108.  * @param left 
          109.  * @param right 
          110.  * @param pivot 
          111.  * @return 
          112.  */  
          113.     public int partitionIt(int left, int right, long pivot) {  
          114.         int leftPtr = left;//定位到最左元素  
          115.         int rightPtr = right-1;//定位到枢纽  
          116.   
          117.         while (true) {  
          118.             while (theArray[++leftPtr] < pivot);//寻找大于枢纽元素  
          119.             while (theArray[--rightPtr] > pivot);//寻找小于枢纽元素  
          120.             if (leftPtr >= rightPtr) {//确定划分结束退出循环  
          121.                 break;  
          122.             } else {  
          123.                 swap(leftPtr, rightPtr);//交换需划分的元素  
          124.             }  
          125.         }  
          126.         swap(leftPtr, right-1);//恢复枢纽到正确位置  
          127.         return leftPtr;//返回枢纽  
          128.     }  
          129. /** 
          130.  * 手动排序 
          131.  * @param left 
          132.  * @param right 
          133.  */  
          134.     public void manualSort(int left, int right) {  
          135.         int size = right-left + 1;  
          136.         if (size <= 1) {//当元素为1时直接返回  
          137.             return;  
          138.         }  
          139.         if (size == 2) {  
          140.             if (theArray[left] > theArray[right]) {//当元素为2时排序  
          141.                 swap(left, right);  
          142.             }  
          143.             return;  
          144.         } else {//当元素为3时排序  
          145.             if (theArray[left] > theArray[right - 1]) {  
          146.                 swap(left, right - 1);  
          147.             }  
          148.             if (theArray[left] > theArray[right]) {  
          149.                 swap(left, right);  
          150.             }  
          151.             if (theArray[right - 1] > theArray[right]) {  
          152.                 swap(right - 1, right);  
          153.             }  
          154.         }  
          155.     }  
          156. }  
          157.   
          158. /** 
          159.  * 主类 
          160.  */  
          161. public class QuickSort2 {  
          162.   
          163.   
          164.     public static void main(String[] args) {  
          165.         int maxSize = 15;  
          166.         ArrayIns arr = new ArrayIns(maxSize);  
          167.         for (int j = 0; j < maxSize; j++) {//随机生机数据插入数组中  
          168.             long n = (int) (java.lang.Math.random() * 99);  
          169.             arr.insert(n);  
          170.         }  
          171.         System.out.println("显示排序前数据");  
          172.         arr.display();  
          173.         arr.quickSort();  
          174.         System.out.println("显示排序后数据");  
          175.         arr.display();  
          176.     }  
          177. }  
          178.   
          179. /** 
          180.  *运行结果: 
          181.  *显示排序前数据 
          182.  *A=38 62 44 89 50 91 36 60 47 22 83 7 33 31 38 
          183.  *显示排序后数据 
          184.  *A=7 22 31 33 36 38 38 44 47 50 60 62 83 89 91  
          185.  */  
          186.   
          187. /** 
          188.  * 总结: 
          189.  * 快速排序是常用排序中效率最高的一种排序方式。 
          190.  * 但在应用中的一此特殊情况影响他的效率,这不是算法本身的问题,而是如果实现的问题。 
          191.  * 三数据项选中方法很好的解决了这样的问题。 
          192.  */ 
      1. /** 
      2.  * @author SunnyMoon 
      3.  */  
      4.   
      5. /********** 
      6.  * 概念介绍: 
      7.  * ******** 
      8.  *处理小划分: 
      9.  * 1. 如果使用三数据项取中值的方法取枢纽,这时快速排序算法不能执行三个或者小于三个数据项 
      10.  * 的划分规则,这时数字3就为排序算法的切割点。在上一篇中对三个或三个以下的数据排序时 
      11.  * 使用手动的方式排序,这种方式实践中不是最好的选择。 
      12.  * 2. 处理小划分的另一个选择是使用插入排序,当使用插入排序时可以将划分设定为10或其它任何 
      13.  * 数,试验不同的切割点的值以找到最佳的切割点,专家推荐使用9为切割点。对小的子数组使用 
      14.  * 插入排序被证时为最快的一种方法。将插入排序和快速排序相结合,可以把快速排序的性能发挥 
      15.  * 到极极,本篇程序使用该方法。 
      16.  * 4. 第三个选择是对数组整个使用快速排序不考虑处理小划分,当结束时数据基本有序了,然后 
      17.  * 使用插入排序对数据排序。因为插入排序对基本有序的数组执行效率很高,许多专家提倡使用 
      18.  * 这种方法,但是插入排序对小规模的数据排序很适合,随着数据规模的扩大性能下降明显。 
      19.  * 
      20.  * 消除递归: 
      21.  * 很多人提倡对快速排序算法进行修改,取消递归包括重写算法用栈实践。但是对于现在的 
      22.  * 系统来说消除递归所带来的改进不是很明显。 
      23.  */  
      24. class ArrayIns {  
      25.   
      26.     private long[] theArray;  
      27.     private int nElems;  
      28.   
      29.     public ArrayIns(int max) {  
      30.         theArray = new long[max];  
      31.         nElems = 0;  
      32.     }  
      33.   
      34.     public void insert(long value) {  
      35.         theArray[nElems] = value;  
      36.         nElems++;  
      37.     }  
      38.   
      39.     public void display() {  
      40.         System.out.print("A=");  
      41.         for (int j = 0; j < nElems; j++) {  
      42.             System.out.print(theArray[j] + " ");  
      43.         }  
      44.         System.out.println("");  
      45.     }  
      46.   
      47.     /** 
      48.      * 快速排序主方法 
      49.      */  
      50.     public void quickSort() {  
      51.         recQuickSort(0, nElems - 1);  
      52.     }  
      53.   
      54.     /** 
      55.      * 递归调用快速的排序核心方法 
      56.      * @param left 
      57.      * @param right 
      58.      */  
      59.     public void recQuickSort(int left, int right) {  
      60.         int size = right - left + 1;  
      61.         if (size < 10) {  
      62.             insertionSort(left, right);  
      63.         } else {  
      64.             long median = medianOf3(left, right);//三数取中值  
      65.             int partition = partitionIt(left, right, median);//三数据取中值作为枢纽进行划分  
      66.             recQuickSort(left, partition - 1);//递归排序数组左子元素  
      67.             recQuickSort(partition + 1, right);//递归排序数据左子元素  
      68.         }  
      69.     }  
      70.   
      71.     /** 
      72.      * 三数据选中 
      73.      * @param left 
      74.      * @param right 
      75.      * @return 
      76.      */  
      77.     public long medianOf3(int left, int right) {  
      78.         int center = (left + right) / 2;  
      79.   
      80.         if (theArray[left] > theArray[center]) {  
      81.             swap(left, center);  
      82.         }  
      83.         if (theArray[left] > theArray[right]) {  
      84.             swap(left, right);  
      85.         }  
      86.         if (theArray[center] > theArray[right]) {  
      87.             swap(center, right);  
      88.         }  
      89.         swap(center, right - 1);  
      90.         return theArray[right - 1];  
      91.     }  
      92.   
      93.     /** 
      94.      * 交换数据 
      95.      * @param dex1 
      96.      * @param dex2 
      97.      */  
      98.     public void swap(int dex1, int dex2) {  
      99.         long temp = theArray[dex1];  
      100.         theArray[dex1] = theArray[dex2];  
      101.         theArray[dex2] = temp;  
      102.     }  
      103.   
      104.     /** 
      105.      * 根据三数据选中进行划分 
      106.      * @param left 
      107.      * @param right 
      108.      * @param pivot 
      109.      * @return 
      110.      */  
      111.     public int partitionIt(int left, int right, long pivot) {  
      112.         int leftPtr = left;//定位到最左元素  
      113.         int rightPtr = right - 1;//定位到枢纽  
      114.   
      115.         while (true) {  
      116.             while (theArray[++leftPtr] < pivot);//寻找大于枢纽元素  
      117.             while (theArray[--rightPtr] > pivot);//寻找小于枢纽元素  
      118.             if (leftPtr >= rightPtr) {//确定划分结束退出循环  
      119.                 break;  
      120.             } else {  
      121.                 swap(leftPtr, rightPtr);//交换需划分的元素  
      122.             }  
      123.         }  
      124.         swap(leftPtr, right - 1);//恢复枢纽到正确位置  
      125.         return leftPtr;//返回枢纽  
      126.     }  
      127.   
      128.     /** 
      129.      * 手动排序 
      130.      * @param left 
      131.      * @param right 
      132.      */  
      133.   
      134.     public void insertionSort(int left, int right) {  
      135.         int in, out;//in为内循环指针,out为外循环指针  
      136.   
      137.         for (out = left + 1; out <= right; out++) {  
      138.             long temp = theArray[out];//移除当前标记元素到临时变量  
      139.             in = out;//定位内循环  
      140.   
      141.             while (in > left && theArray[in - 1] >= temp) {//满足条件时向左移动元素  
      142.                 theArray[in] = theArray[in - 1];  
      143.                 --in;  
      144.             }  
      145.             theArray[in] = temp;//插入当前标记元素到正确位置  
      146.         }  
      147.     }  
      148. }  
      149.   
      150. /** 
      151.  * 主类 
      152.  */  
      153. public class QuickSort3 {  
      154.   
      155.     public static void main(String[] args) {  
      156.         int maxSize = 10;  
      157.         ArrayIns arr = new ArrayIns(maxSize);  
      158.         for (int j = 0; j < maxSize; j++) {//随机生机数据插入数组中  
      159.             long n = (int) (java.lang.Math.random() * 99);  
      160.             arr.insert(n);  
      161.         }  
      162.         System.out.println("显示排序前数据");  
      163.         arr.display();  
      164.         arr.quickSort();  
      165.         System.out.println("显示排序后数据");  
      166.         arr.display();  
      167.     }  
      168. }  
      169. /** 
      170.  * 运行结果: 
      171.  * 显示排序前数据 
      172.  * A=56 14 50 18 82 58 30 50 60 1 
      173.  * 显示排序后数据 
      174.  * A=1 14 18 30 50 50 56 58 60 82 
      175.  */  
      176.   
      177. /** 
      178.  * 总结: 
      179.  * 快速排序是常用排序中效率最高的一种排序方式。 
      180.  * 但在应用中的一此特殊情况影响他的效率,这不是算法本身的问题,而是如果实现的问题。 
      181.  * 三数据项选中方法很好的解决了这样的问题。三数据选中方法不是最好的选择,可以将插入排序 
      182.  * 与快速排序相结合的方式解决这样的问题,使快速排序算法发挥到极致。 
      183.  */ 
原文地址:https://www.cnblogs.com/biggestfish/p/2927050.html