快速排序及拓展
- 快排的递归版本和非递归版本。
- 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。(29)
- 输入n个数,找出其中最小的k个数。(30)
1、思路:
递归版本:首先随机选定分割数,对数组中小于该分割数的放在左侧,大于该分割数的放在右侧。递归处理左侧和右侧的数字。
QuickSort
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <exception> 4 5 void PrintArray(int* data, int length) 6 { 7 for (int i = 0; i < length; i++) 8 printf("%d ", data[i]); 9 printf("\n"); 10 } 11 12 void Swap(int* a, int* b) 13 { 14 int temp; 15 temp = *a; 16 *a = *b; 17 *b = temp; 18 } 19 20 int Random(int min, int max) 21 { 22 int random = rand() % (max - min + 1) + min; 23 return random; 24 } 25 26 int Partition(int* data, int start, int end) 27 { 28 int index = Random(start, end); 29 Swap(&data[index], &data[end]); 30 int small = start; 31 for (index = start; index < end; index++) 32 { 33 if (data[index] < data[end]) 34 { 35 Swap(&data[small], &data[index]); 36 small++; 37 } 38 } 39 Swap(&data[small], &data[end]); 40 return small; 41 } 42 43 void QuickSort(int* data, int start, int end) 44 { 45 if (start == end) 46 return; 47 int index = Partition(data, start, end); 48 if (index > start) 49 QuickSort(data, start, index - 1); 50 if (index < end) 51 QuickSort(data, index + 1, end); 52 } 53 54 int main() 55 { 56 int test[7] = {23, 13, 49, 6, 31, 19, 28}; 57 PrintArray(test, 7); 58 QuickSort(test, 7, 0, 6); 59 PrintArray(test, 7); 60 }
非递归版本:用数组和下标来模拟栈的操作。
1 #include <stdlib.h> 2 #include <stdio.h> 3 #define SIZE 1000 4 5 typedef struct _stackNode 6 { 7 int low; 8 int high; 9 }stackNode; 10 11 void PrintArray(int data[], int len) 12 { 13 for (int i = 0; i < len; i++) 14 printf("%d ", data[i]); 15 printf("\n"); 16 } 17 18 void Swap(int* a, int* b) 19 { 20 int temp; 21 temp = *a; 22 *a = *b; 23 *b = temp; 24 } 25 26 int Random(int min, int max) 27 { 28 int r = rand() % (max - min + 1) + min; 29 return r; 30 } 31 32 int Partition(int* data, int start, int end) 33 { 34 int index = Random(start, end); 35 Swap(&data[index], &data[end]); 36 int small = start; 37 for (index = start; index < end; index++) 38 { 39 if (data[index] < data[end]) 40 { 41 Swap(&data[small], &data[index]); 42 small++; 43 } 44 } 45 Swap(&data[small], &data[end]); 46 return small; 47 } 48 49 void quickSortNoneRecursive(int data[], int len) 50 { 51 int low, high, mid, top; 52 stackNode* st; 53 if ((st = (stackNode*)malloc(sizeof(stackNode) * SIZE)) == NULL) 54 { 55 printf("malloc fail!\n"); 56 exit(0); 57 } 58 top = 0; 59 st[top].low = 0; 60 st[top].high = len - 1; 61 62 while (top >= 0) 63 { 64 low = st[top].low; 65 high = st[top].high; 66 top--; 67 if (low < high) 68 { 69 mid = Partition(data, low, high); 70 if (low < mid) 71 { 72 top++; 73 st[top].low = low; 74 st[top].high = mid - 1; 75 } 76 if (high > mid) 77 { 78 top++; 79 st[top].low = mid + 1; 80 st[top].high = high; 81 } 82 } 83 } 84 free(st); 85 } 86 87 int main() 88 { 89 int *data = (int*)malloc(sizeof(int) * SIZE); 90 for (int i = 0; i < SIZE; i++) 91 data[i] = rand() % SIZE; 92 PrintArray(data, 50); 93 quickSortNoneRecursive(data, SIZE); 94 PrintArray(data, 50); 95 return 0; 96 }
2、思路:
因为一个数字的出现超过一半,所以他一定会出现在数组的中间。则用快速选择的方法,当找到中间位置即是该数。
1 int MoreThanHalfNum_1(int* numbers, int length) 2 { 3 assert(numbers && length >= 0); 4 int middle = length >> 1; 5 int start = 0; 6 int end = length - 1; 7 int index = Partition(numbers, length, start, end); 8 9 while (index != middle) 10 { 11 if (index > middle) 12 { 13 end = index - 1; 14 index = Partition(numbers, length, start, end); 15 } 16 else 17 { 18 start = index + 1; 19 index = Partition(numbers, length, start, end); 20 } 21 } 22 23 int result = numbers[middle]; 24 return result; 25 }
3、思路:
基于数组的第k个数来做调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。但是最小的k个数字是没有排序的,另外也会更改原数组的位置。而且该算法要求所有n个数都要一次性放入内存,这对海量数据不合适。
GetLeastNumbers
1 void GetLeastNumbers_Solution1(int* input, int n, int* output, int k) 2 { 3 if(input == NULL || output == NULL || k > n || n <= 0 || k <= 0) 4 return; 5 6 int start = 0; 7 int end = n - 1; 8 int index = Partition(input, n, start, end); 9 while(index != k - 1) 10 { 11 if(index > k - 1) 12 { 13 end = index - 1; 14 index = Partition(input, n, start, end); 15 } 16 else 17 { 18 start = index + 1; 19 index = Partition(input, n, start, end); 20 } 21 } 22 23 for(int i = 0; i < k; ++i) 24 output[i] = input[i]; 25 }