排序 O(nlogn)
1.
堆排序是一种优秀的排序算法,时间复杂度O(nlogn),主要思想是用数组构造一个最大堆,满足跟节点的value>子节点的value,然后将堆顶元素(value最大)与最后一个叶子节点交换,再调整堆,使其满足最大堆的性质,重复上述步骤n-1次后就得到一个有序序列。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define MAX 111111 5 #define LEFT(i) (i << 1) 6 #define RIGHT(i) (i << 1|1) 7 using namespace std; 8 int a[MAX], Heap_Size, a_Length; 9 void Max_Heapify(int i){ 10 int largest, l, r; 11 l = LEFT(i); 12 r = RIGHT(i); 13 if(l <= Heap_Size && a[l] > a[i]) largest = l; 14 else largest = i; 15 if(r <= Heap_Size && a[r] > a[largest]) largest = r; 16 if(largest != i){ 17 int temp = a[i]; 18 a[i] = a[largest]; 19 a[largest] = temp; 20 Max_Heapify(largest); 21 } 22 return; 23 } 24 void Build_Heap(){ 25 for(int i = a_Length/2; i >= 1; i --) 26 Max_Heapify(i); 27 return; 28 } 29 void Heap_Sort(){ 30 Build_Heap(); 31 for(int i = a_Length; i >= 2; i --){ 32 int temp = a[1]; 33 a[1] = a[i]; 34 a[i] = temp; 35 Heap_Size--; 36 Max_Heapify(1); 37 } 38 return ; 39 } 40 int main(){ 41 freopen("data.cpp", "r", stdin); 42 freopen("out.cpp", "w", stdout); 43 while(~scanf("%d", &a_Length)){ 44 Heap_Size = a_Length; 45 for(int i = 1; i <= a_Length; i ++) scanf("%d", a+i); 46 Heap_Sort(); 47 printf("Length = %d\n", a_Length); 48 for(int i = 1; i < a_Length; i ++) printf("%d ", a[i]); 49 printf("%d\n\n\n", a[a_Length]); 50 } 51 return 0; 52 }
2.
快速排序:主要思想就是随机选定一个数x,以该数为基准,将数组划分,左边都小于或等于它,右边都大于它,这样就将数组划分成左右两部分,而数x则是处于正确位置,然后再重复上述过程分别处理左右部分,直到数组有序。时间复杂度O(nlogn).
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #define MAX 111111 6 using namespace std; 7 int a[MAX], a_length; 8 int Rand_Partition(int p, int r){ 9 int x = a[r], i = p-1; 10 for(int j = p; j < r; j ++){ 11 if(a[j] <= x){ 12 i ++; 13 int temp = a[i]; 14 a[i] = a[j]; 15 a[j] = temp; 16 } 17 } 18 a[r] = a[i+1]; 19 a[i+1] = x; 20 return i+1; 21 } 22 void Qucik_Sort(int p, int r){ 23 if(p < r){ //与调用Rand_Partition()函数效果一样; 24 int i = p-1; 25 for(int j = p; j < r; j ++){ 26 if(a[j] <= a[r]){ 27 i ++; 28 swap(a[i], a[j]); 29 } 30 } 31 swap(a[r], a[i+1]); 32 int q = i+1; //end; 33 /* int q = Rand_Partition(p, r); */ 34 Qucik_Sort(p, q-1); 35 Qucik_Sort(q+1, r); 36 } 37 } 38 int main(){ 39 freopen("data.cpp", "r", stdin); 40 freopen("Quick_sort_out.cpp", "w", stdout); 41 while(~scanf("%d", &a_length)){ 42 printf("Length = %d\n", a_length); 43 for(int i = 0; i < a_length; i ++) scanf("%d", a+i); 44 Qucik_Sort(0, a_length-1); 45 for(int i = 0; i < a_length-1; i ++) printf("%d ", a[i]); 46 printf("%d\n\n\n", a[a_length-1]); 47 } 48 return 0; 49 }
3.
归并排序,采用分治策略,主要思想是假定数组a和b已经是有序的,那么可以在O(n)的时间内将他们合并成一个有序序列,现在将数组平均分成两部分,但这两部分并不是有序的,因此需要再次将这两个部分再分,使问题规模逐渐变小,继续递归划分,当子数组足够小时(即只有一个元素),可以直接求解,因为此时一个元素就是有序的。然后就可以合并这两个部分了,合并完之后就形成一个局部有序序列(我们最终要得到整个有序序列),此时向上回溯与其他有序部分进行合并,当回溯到跟节点时,整个序列就合并完毕,因此得到一个有序序列。
分治策略一般分为三步:(1):分解原问题使问题规模变小以便我们直接处理,对于上述问题就是将原序列分解,当分解到子序列只有一个元素时就可直接求解(因为一个元素的序列已经是有序的了);(2)治,即解决问题;(3)合并,将子问题解决之后要向上合并从而得到原问题的解。
分治策略一般使用递归来实现。
1 #include<stdio.h> 2 #include<string.h> 3 int a[1000005]; 4 int l[100005]; 5 int r[100005]; 6 void merge(int p, int mid, int q) 7 { 8 int nl = mid - p + 1; 9 int nr = q - mid; 10 int i, j, k; 11 for(i = 0; i < nl; i ++) 12 l[i] = a[p+i]; 13 for(i = 1; i <= nr; i ++) 14 r[i - 1] = a[mid+i]; 15 l[nl] = 1 << 30; 16 r[nr] = 1 << 30; 17 i = 0; 18 j = 0; 19 for(k = p; k <= q; k ++) 20 { 21 if(l[i] <= r[j]) 22 a[k] = l[i++]; 23 else 24 a[k] = r[j++]; 25 } 26 } 27 28 void merge_sort(int l, int r) 29 { 30 if(l < r) 31 { 32 int mid = (l + r) >> 1; 33 merge_sort(l, mid); 34 merge_sort(mid + 1, r); 35 merge(l, mid, r); 36 } 37 } 38 39 int main(int argc, char const *argv[]) 40 { 41 int n, i; 42 freopen("data.cpp", "r", stdin); 43 freopen("Merge_out.cpp", "w", stdout); 44 while(~scanf("%d", &n)) 45 { 46 printf("Length = %d\n", n); 47 for(i = 0; i < n; i ++) 48 scanf("%d", &a[i]); 49 merge_sort(0, n-1); 50 for(i = 0; i < n-1; i ++) 51 printf("%d ",a[i]); 52 printf("%d\n\n\n", a[i]); 53 } 54 return 0; 55 }
4.
最后一个是用二叉搜索树通过中序遍历得到的有序序列,时间复杂度也是O(nlogn)较简单和容易理解。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<stack> 5 using namespace std; 6 typedef struct Node{ 7 int key; 8 Node *left; 9 Node *right; 10 Node(){ 11 left = NULL; 12 right = NULL; 13 } 14 }Node; 15 Node *root; 16 stack<Node*>s; 17 void Insert(int key){ 18 Node *tmp = new Node(); 19 tmp->key = key; 20 Node *ff = root; 21 Node *flag = NULL; 22 while(ff){ 23 flag = ff; 24 if(key <= ff->key) ff = ff->left; 25 else ff = ff->right; 26 } 27 if(flag == NULL){ 28 root = new Node(); 29 root->key = key; 30 return; 31 } 32 if(flag->key >= key) flag->left = tmp; 33 else flag->right = tmp; 34 } 35 36 void Visist_Treee_1(Node *tmp){ 37 if(tmp){ 38 Visist_Treee_1(tmp->left); 39 printf("%d ", tmp->key); 40 Visist_Treee_1(tmp->right); 41 } 42 } 43 44 /* void Visist_Treee_2(Node *tmp){ */ 45 /* while(!s.empty()) s.pop(); */ 46 /* s.push(tmp); */ 47 /* while(!s.empty()){ */ 48 /* Node *p = s.top(); */ 49 /* s.pop(); */ 50 /* while(p->left) s.push(p), p = p->left; */ 51 /* Node *q = s.top(); */ 52 /* s.pop(); */ 53 /* printf("%d ", q->key); */ 54 /* if(q->right) s.push(q); */ 55 /* } */ 56 /* } */ 57 58 int main(){ 59 int n, temp; 60 freopen("data.cpp", "r", stdin); 61 freopen("Binary_Tree_out.cpp", "w", stdout); 62 while(~scanf("%d", &n)){ 63 root = NULL; 64 printf("Length = %d\n", n); 65 for(int i = 0; i < n; i ++){ 66 scanf("%d", &temp); 67 Insert(temp); 68 } 69 Visist_Treee_1(root); 70 printf("\n\n\n"); 71 /* Visist_Treee_2(root); */ 72 } 73 }