堆排序 看张我百度的gif图片,了解大根堆的性质,那么你就可以读下面的代码了。代码中有详尽的解释。
public static void heapSort(int[] array) { int length = array.length - 1; initHeapSort(array, length); System.out.println("堆: " + Arrays.toString(array)); for (int k = 0; k < array.length - 1; k++) { change(array, length, 0); length--; heapchange(array, length); } }
private static void initHeapSort(int[] array, int length) { /** * 初始化大根堆,每次堆中添加一个数组的元素,用此元素与父节点比较交换, *交换后父节点(此时是你添加的元素)与父节点的父节点比较,直到父节点为根节点结束比较,来保证大根堆。 */ for (int j = 1; j <= length; j++) { int k = j; int father = (k - 1) / 2; while (father >= 0 && k > 0) { if (array[k] > array[father]) { change(array, father, k); } System.out.println("交换后数组: " + Arrays.toString(array) + "j: " + j); k = father; father = (father - 1) / 2; } } }
private static void heapchange(int[] array, int length) { /** * 当堆稳定时,交换堆最后一个元素和第一个元素,保持最后一个元素不动(用最大下标 array.length --), * 判断根节点左右孩子是否存在,并比较大小,最大的和父节点交换,然后保证没有交换的一支不动,调整交换过的堆使堆稳定。然后重复上述步骤。 */ int father = 0;//从堆顶开始 int leftChild = 2 * father + 1; int rightChild = leftChild + 1; while (leftChild <= length ) {//当父节点没有孩子节点,是叶子节点,跳出循环 //比较父节点和他的孩子节点,如果有大于它的,判断是左孩子还是右孩子交换 if (rightChild <= length && (array[leftChild] > array[father] || array[rightChild] > array[father])) { //判断 rightChild <=length 保证在没有右孩子节点时只比较左孩子节点。 if (array[leftChild] > array[rightChild]) { change(array, father, leftChild); father = leftChild; }else { change(array, father, rightChild); father = rightChild; } }else if (array[leftChild] > array[father]) { //当父节点只有一个左孩子节点(叶子节点)时,交换完之后就可以跳出循环, //说明:对于完全二叉树,满足此条件的父节点的子节点一定是叶子节点 change(array, father, leftChild); break; }else { //当父节点没有和孩子节点交换,那么父节点下移,令左孩子节点为新一任父节点 //(说明:右孩子节点不一定有,左孩子节点可以有,如果没有的话,此节点为叶子节点while()条件本意就是在判断是否是叶子节点) father = 2 * father + 1; } leftChild = 2 * father + 1; rightChild = leftChild + 1; } }
private static void change(int[] array, int max, int k) { int temp = array[max]; array[max] = array[k]; array[k] = temp; // array[max] ^= array[k]; // array[k] ^= array[max]; // array[max] ^= array[k]; }