文章目录
- 说明
- day48 堆排序
- 1.基本思路
- 2.代码
说明
闵老师的文章链接: 日撸 Java 三百行(总述)_minfanphd的博客-CSDN博客
自己也把手敲的代码放在了github上维护:https://github.com/fulisha-ok/sampledata
day48 堆排序
1.基本思路
(1)大/小顶堆:每一个结点值都大于(小于)或等于孩子结点(实际上堆可以看成一颗完全二叉树)
(2)堆排序:利用这种堆的结构进行排序。如:对一个待排序列进行堆排序,需要先建堆(大顶堆),这时我们可以结合大顶堆的性质,取堆顶元素,取完堆顶元素后我们要重新调整大顶堆,再取堆顶数据再调整。在这个过程会涉及建堆,调整堆。所以要清楚这个堆有什么特点。
(3)堆:堆通常是一个可以被看做一棵完全二叉树的数组对象,因为堆可以看做是完全二叉树。则完全二叉树的特点:
-
a. 假设完全二叉树总节点数为n,则会有n/2个父节点
-
b. 对一棵有n个结点的完全二叉树的结点按层序编号, 则对任一结点i (1≤i≤n) ,若2i>n,则结点i无左孩子,否则左孩子的结点为2i;如果2i+1>n,则结点i无右孩子,否则右孩子结点为2i+1
-
c. 完全二叉树的叶子结点也只能出现最后两层上
对于上面完全二叉树中a,b中这个关系对我们进行堆排序进行构建堆,调整堆很关键。
(4)手动模拟构造堆:(为了方便理解,我这里下标i从1开始, n=8)
-
step1:对待排序数组按完全二叉树方式排列出来; 调整堆:自下往上逐步调整。先找到最后一个父节点n/2=4,判断i=4结点的孩子结点较大是否大于父节点,若大于则交换数据
-
step2-5:继续向上调整,调整过程和step1一样,但是在调整的过程中,可能会破坏下一级的大顶堆结构,所以还需要向下检查,例如图中step4中i=1中53和87交换后,破坏了i=3处大顶堆的结构,则需要调整。
-
在大顶堆构造好后,将根结点与最后一个结点交换位置后又重新开始调整堆(如下图)
用代码跑出来的堆排序结果:
-------heapSortTest-------
I am a data array with 8 items.
(53, if) (17, then) (78, else) (9, switch) (45, case) (65, for) (87, while) (32, break)
The parent position is 3 and the child is 7
Move 32 to position 3
Adjust 3 to 8: I am a data array with 8 items.
(53, if) (17, then) (78, else) (32, break) (45, case) (65, for) (87, while) (9, switch)
The parent position is 2 and the child is 6
Move 87 to position 2
Adjust 2 to 8: I am a data array with 8 items.
(53, if) (17, then) (87, while) (32, break) (45, case) (65, for) (78, else) (9, switch)
The parent position is 1 and the child is 4
Move 45 to position 1
Adjust 1 to 8: I am a data array with 8 items.
(53, if) (45, case) (87, while) (32, break) (17, then) (65, for) (78, else) (9, switch)
The parent position is 0 and the child is 2
Move 87 to position 0
The parent position is 2 and the child is 6
Move 78 to position 2
Adjust 0 to 8: I am a data array with 8 items.
(87, while) (45, case) (78, else) (32, break) (17, then) (65, for) (53, if) (9, switch)
The initial heap: I am a data array with 8 items.
(87, while) (45, case) (78, else) (32, break) (17, then) (65, for) (53, if) (9, switch)
The parent position is 0 and the child is 2
Move 78 to position 0
The parent position is 2 and the child is 5
Move 65 to position 2
Adjust 0 to 7: I am a data array with 8 items.
(78, else) (45, case) (65, for) (32, break) (17, then) (9, switch) (53, if) (87, while)
Round 1: I am a data array with 8 items.
(78, else) (45, case) (65, for) (32, break) (17, then) (9, switch) (53, if) (87, while)
The parent position is 0 and the child is 2
Move 65 to position 0
The parent position is 2 and the child is 5
Adjust 0 to 6: I am a data array with 8 items.
(65, for) (45, case) (53, if) (32, break) (17, then) (9, switch) (78, else) (87, while)
Round 2: I am a data array with 8 items.
(65, for) (45, case) (53, if) (32, break) (17, then) (9, switch) (78, else) (87, while)
The parent position is 0 and the child is 2
Move 53 to position 0
Adjust 0 to 5: I am a data array with 8 items.
(53, if) (45, case) (9, switch) (32, break) (17, then) (65, for) (78, else) (87, while)
Round 3: I am a data array with 8 items.
(53, if) (45, case) (9, switch) (32, break) (17, then) (65, for) (78, else) (87, while)
The parent position is 0 and the child is 1
Move 45 to position 0
The parent position is 1 and the child is 3
Move 32 to position 1
Adjust 0 to 4: I am a data array with 8 items.
(45, case) (32, break) (9, switch) (17, then) (53, if) (65, for) (78, else) (87, while)
Round 4: I am a data array with 8 items.
(45, case) (32, break) (9, switch) (17, then) (53, if) (65, for) (78, else) (87, while)
The parent position is 0 and the child is 1
Move 32 to position 0
Adjust 0 to 3: I am a data array with 8 items.
(32, break) (17, then) (9, switch) (45, case) (53, if) (65, for) (78, else) (87, while)
Round 5: I am a data array with 8 items.
(32, break) (17, then) (9, switch) (45, case) (53, if) (65, for) (78, else) (87, while)
The parent position is 0 and the child is 1
Move 17 to position 0
Adjust 0 to 2: I am a data array with 8 items.
(17, then) (9, switch) (32, break) (45, case) (53, if) (65, for) (78, else) (87, while)
Round 6: I am a data array with 8 items.
(17, then) (9, switch) (32, break) (45, case) (53, if) (65, for) (78, else) (87, while)
Adjust 0 to 1: I am a data array with 8 items.
(9, switch) (17, then) (32, break) (45, case) (53, if) (65, for) (78, else) (87, while)
Round 7: I am a data array with 8 items.
(9, switch) (17, then) (32, break) (45, case) (53, if) (65, for) (78, else) (87, while)
Result
I am a data array with 8 items.
(9, switch) (17, then) (32, break) (45, case) (53, if) (65, for) (78, else) (87, while)
2.代码
堆排序我觉得一定要借助图像,不然很难仅用脑子去想象这个过程。
-
(1)结合文章的代码,需要注意的是这里下标i不是从1开始的,是从0开始的,则i其左孩子结点为2i+1,右孩子结点为2i
-
(2)先看**adjustHeap(int paraStart, int paraLength)**这个方法中,for循环是根据i处父节点向下去筛选最大的结点,第一个if是判断父节点的孩子结点中的最大结点 第二个if则是与父节点进行比较,是否大于父节点,若大于则需要交换位置,在这里,交换了父节点并不能确定父节点的最终位置,因为可能交换了位置会破坏下面的堆结构,还需要向下继续调整。
-
(3)堆排序方法heapSort(),第一个for循环是构建初始堆,第二个循环则是在循环输出堆排序,我们从代码也可以看到,每取一个堆顶元素则要进行一次堆调整
/**
* heap sort. Maybe the most difficult sorting algorithm.
*/
public void heapSort() {
DataNode tempNode;
//step1 Construct the initial heap
for (int i = length/2 -1 ; i >= 0; i--){
adjustHeap(i, length);
}
System.out.println("The initial heap: " + this + "\r\n");
//step2 swap and reconstruct
for (int i = length -1; i > 0; i--) {
tempNode = data[0];
data[0] = data[i];
data[i] = tempNode;
adjustHeap(0, i);
System.out.println("Round " + (length - i) + ": " + this);
}
}
/**
* Adjust the heap
* @param paraStart the start of the index
* @param paraLength the length of the adjusted sequence
*/
public void adjustHeap(int paraStart, int paraLength) {
DataNode tempNode = data[paraStart];
int tempParent = paraStart;
int tempKey = data[paraStart].key;
for (int tempChild = paraStart*2 + 1; tempChild < paraLength; tempChild = tempChild*2 + 1) {
//the right child is bigger
if (tempChild + 1 < paraLength) {
if (data[tempChild].key < data[tempChild+1].key) {
tempChild++;
}
}
System.out.println("The parent position is " + tempParent + " and the child is " + tempChild);
if (tempKey < data[tempChild].key) {
// the child is bigger
data[tempParent] = data[tempChild];
System.out.println("Move " + data[tempChild].key + " to position " + tempParent);
tempParent = tempChild;
} else {
break;
}
}
data[tempParent] = tempNode;
System.out.println("Adjust " + paraStart + " to " + paraLength + ": " + this);
}
public static void heapSortTest() {
int[] tempUnsortedKeys = { 5, 3, 6, 10, 7, 1, 9 };
//int[] tempUnsortedKeys = { 53, 17, 78, 9, 45, 65, 87, 32};
String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
// String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" , "break"};
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
tempDataArray.heapSort();
System.out.println("Result\r\n" + tempDataArray);
}
运行结果:
-------heapSortTest-------
I am a data array with 7 items.
(5, if) (3, then) (6, else) (10, switch) (7, case) (1, for) (9, while)
The parent position is 2 and the child is 6
Move 9 to position 2
Adjust 2 to 7: I am a data array with 7 items.
(5, if) (3, then) (9, while) (10, switch) (7, case) (1, for) (6, else)
The parent position is 1 and the child is 3
Move 10 to position 1
Adjust 1 to 7: I am a data array with 7 items.
(5, if) (10, switch) (9, while) (3, then) (7, case) (1, for) (6, else)
The parent position is 0 and the child is 1
Move 10 to position 0
The parent position is 1 and the child is 4
Move 7 to position 1
Adjust 0 to 7: I am a data array with 7 items.
(10, switch) (7, case) (9, while) (3, then) (5, if) (1, for) (6, else)
The initial heap: I am a data array with 7 items.
(10, switch) (7, case) (9, while) (3, then) (5, if) (1, for) (6, else)
The parent position is 0 and the child is 2
Move 9 to position 0
The parent position is 2 and the child is 5
Adjust 0 to 6: I am a data array with 7 items.
(9, while) (7, case) (6, else) (3, then) (5, if) (1, for) (10, switch)
Round 1: I am a data array with 7 items.
(9, while) (7, case) (6, else) (3, then) (5, if) (1, for) (10, switch)
The parent position is 0 and the child is 1
Move 7 to position 0
The parent position is 1 and the child is 4
Move 5 to position 1
Adjust 0 to 5: I am a data array with 7 items.
(7, case) (5, if) (6, else) (3, then) (1, for) (9, while) (10, switch)
Round 2: I am a data array with 7 items.
(7, case) (5, if) (6, else) (3, then) (1, for) (9, while) (10, switch)
The parent position is 0 and the child is 2
Move 6 to position 0
Adjust 0 to 4: I am a data array with 7 items.
(6, else) (5, if) (1, for) (3, then) (7, case) (9, while) (10, switch)
Round 3: I am a data array with 7 items.
(6, else) (5, if) (1, for) (3, then) (7, case) (9, while) (10, switch)
The parent position is 0 and the child is 1
Move 5 to position 0
Adjust 0 to 3: I am a data array with 7 items.
(5, if) (3, then) (1, for) (6, else) (7, case) (9, while) (10, switch)
Round 4: I am a data array with 7 items.
(5, if) (3, then) (1, for) (6, else) (7, case) (9, while) (10, switch)
The parent position is 0 and the child is 1
Move 3 to position 0
Adjust 0 to 2: I am a data array with 7 items.
(3, then) (1, for) (5, if) (6, else) (7, case) (9, while) (10, switch)
Round 5: I am a data array with 7 items.
(3, then) (1, for) (5, if) (6, else) (7, case) (9, while) (10, switch)
Adjust 0 to 1: I am a data array with 7 items.
(1, for) (3, then) (5, if) (6, else) (7, case) (9, while) (10, switch)
Round 6: I am a data array with 7 items.
(1, for) (3, then) (5, if) (6, else) (7, case) (9, while) (10, switch)
Result
I am a data array with 7 items.
(1, for) (3, then) (5, if) (6, else) (7, case) (9, while) (10, switch)