深信服笔试
1 struct还有这种神奇的初始化方式:
struct node{ int v1; int v2; }t{1}; //t.v1 = 1 tt{1, 2}; //tt.v1 = 1 tt.v2 = 2
2 static声明的局部变量 默认初始化
static int sss;
3 堆
一个初始堆是一个完全二叉树
举例说明:
给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序。
首先构建一个二叉树:
然后我们希望调整出一个大顶堆
则从最后一个非叶结点开始调整,过程如下:
找到 节点、左孩子、右孩子 三者中的最大值,放到节点位置上
继续调整该节点父节点之间的位置关系:
后头发现,16 与 17关系不满足,继续自上而下调整它
这样就得到了初始堆 而且还是个 大顶堆。
即每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换(交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整)。有了初始堆之后就可以进行排序了。
下面开始排序了!
20 17 8 7 16 3
把第一个和最后一个元素交换 3 17 8 7 16 20 得到最大元素 20 因为之前已经保证了 堆顶元素最大
去掉最后一个元素 & 调整 得到 : 17 10 8 7 3
把第一个和最后一个元素交换: 3 10 8 7 17 得到最大元素 17 因为之前已经保证了 堆顶元素最大
去掉最后一个元素 & 调整 得到 : 10 7 3 8
把第一个和最后一个元素交换: 8 7 3 10 得到最大元素 10 因为之前已经保证了 堆顶元素最大
去掉最后一个元素 & 调整 得到 : 8 7 3
把第一个和最后一个元素交换: 3 7 8 得到最大元素 8 因为之前已经保证了 堆顶元素最大
去掉最后一个元素 & 调整 得到 : 7 3
把第一个和最后一个元素交换: 3 7 得到最大元素 7 因为之前已经保证了 堆顶元素最大
去掉最后一个元素 & 调整 得到 : 3
把第一个和最后一个元素交换: 3 得到最大元素 3 因为之前已经保证了 堆顶元素最大
去掉最后一个元素 & 调整 得到 : 空 END : 结束排序
实现了:
#include <iostream> #include <cstdio> #include <cstring> #define LS(x) x << 1 #define RS(x) x << 1 | 1 using namespace std; template<class T> void updateMaxHeap(T *a, int i, int n) { int left = LS(i), right = RS(i), largest; if(left > n) return ; largest = left; if(right <= n && a[right] > a[largest]){ largest = right; } if(a[i] < a[largest]){ // 孩子 大于 父节点 需要调整 swap(a[i], a[largest]); updateMaxHeap(a, largest, n); }//如果根节点最大 那么不用继续调整下去了 } template<class T> void create_max_heap(T *a, int n) { // 1...n/2 是树中所有非叶子结点 只需要调整非叶子节点即可 // 倒着调整建堆:这点很重要! for(int i = n/2; i >= 1; i --){ updateMaxHeap(a, i, n); } } template<class T> void heap_sort(T *a, int n) { create_max_heap(a, n); cout<<"Max Heap: "<<endl; for(int i = 1; i <= n; i ++) cout<<a[i]<<" "; for(int i = n; i >= 2; i --){ swap(a[i], a[1]); updateMaxHeap(a, 1, i - 1); } cout<<"Sort: "<<endl; for(int i = 1; i <= n; i ++) cout<<a[i]<<" "; } double nums[100]; int main() { int n; cin>>n; for(int i = 1; i <= n; i ++) cin>>nums[i]; heap_sort(nums, n); return 0; } //1 5 4 2 3 6
最后时间复杂度:
建堆O(n*log2n)
筛选法调整堆O(log2n)
总共循环了n-1次调整函数,所以调整堆时间复杂度为O(n*log2n)
熟悉了堆排序的过程后,可以发现堆排序不存在最佳情况,待排序序列是有序或者逆序时,并不对应于堆排序的最佳或最坏情况。且在最坏情况下时间复杂度也是O(n*log2n)。此外堆排序是不稳定的原地排序算法。