今天自己研究了堆排序,发现个问题,你认证他就很简单你不认真就很难。用心去看任何算法都是很有魅力的,以前复习的时候感觉所有的算法都是背会的,这次复习感觉很爽所有的都是靠理解来处理;下面我就把自己简单的理解写写做个小记录方便后续巩固
1.先把数据构建一个堆,这里我们选用大根堆(就是每个节点的值都不大于其父节点的值)。
处理的具体步骤是从树的第一个非叶子节点开始,一般都是从n/2节点开始,如果2*n<=n 则2*n是其左子节点, 如果2*n+1 <=n。
从n/2节点开始,把n/2节点和其左右子节点中较大的值进行比较,如果子节点的值大于父节点的值那么就交换两者的值。
处理完该节点在下一个非叶子节点重复上面的步骤,如果出现数据交换的情况导致堆被破坏就重新整理调整。直至所有的节点都满足为止。
2.经过上面的处理之后,下面就开始排序,主要就是把堆最后一个子节点n-1的数据和根节点0的数据对换,对换后我们就得到了新的被破坏的堆和排序数组 n,继续按 照步骤1的过程重新调整被破坏的堆,调整完成后把最新的堆的最后一个数据n-2的数据和根节点0的数据对换,...一直重复知道得到我们的排序数组[a0 a1 a2 ... n]为 止。
下面贴个我写的代码
void HeapSort(int* a, int n) { for (int i = n / 2 - 1; i >= 0; i--)//从树的第一个非叶子节点的节点开始,第一个非叶子节点的节点id是n/2 { while (2 * i + 1 < n)//有左节点 { int j = 2 * i + 1; if ((j + 1 < n) && (a[j] < a[j + 1]))//有右侧节点,同时右侧节点大于左侧节点 { ++j; } if (a[i] < a[j])//交换父节点和子节点的数据 { int t = a[i]; a[i] = a[j]; a[j] = t; i = j;//堆被破坏,重新整理 } else { break; } } } //调整完后进行处理 for (int i = n - 1; i > 0; i--) { int t = a[i]; a[i] = a[0]; a[0] = t; //交换完毕,开始重新调整 int k = 0; while (2 * k + 1 < i) { int j = 2 * k + 1; if ((j + 1) < i && a[j] < a[j + 1]) { ++j; } if (a[k] < a[j]) { int t = a[k]; a[k] = a[j]; a[j] = t; k = j; } else { break; } } } } #define MAX_LEN 10 int _tmain(int argc, _TCHAR* argv[]) { int *a = new int[MAX_LEN]; memset(a, 0, MAX_LEN); srand(time_t(NULL)); for (int i = 0; i < MAX_LEN; i++) { a[i] = rand() % 100; printf("%d ", a[i]); } printf(" "); printf("开始排序 "); int tick = GetTickCount(); HeapSort(a, MAX_LEN ); printf(" "); printf("排序用时:%d ", GetTickCount() - tick); for (int i = 0; i < MAX_LEN; i++) { printf("%d ", a[i]); } system("pause"); return 0; }