排序2
本博客的代码的思想和图片参考:好大学慕课浙江大学陈越老师、何钦铭老师的《数据结构》
排序2
1 快速排序
1.1 算法思想
快速排序的主要思想就是分而治之。选择一个主元,然后把原来的集合分为比主元小和比主元大两个子集合,然后递归的解决左边,递归的解决右边。我们使用一幅图片来进行说明
下面是快速排序的伪代码描述
void Quicksort( ElementType A[], int N )
{
if ( N < 2 ) return;
pivot = 从A[]中选一个主元;
将S = { A[] \ pivot } 分成2个独立子集:
A1={ aS | a pivot } 和
A2={ aS | a pivot };
A[] =
Quicksort(A1,N1)U
pivot}U
Quicksort(A2,N2);
}
1.2 快速排序的性能分析
因为快速排序是递归进行的,递归算法的好处体现在每次可以递归的解决规模差不多的子问题。如果主元选的不好,让子集大小很悬殊,那么快速排序就快不起来了。下面是使用一幅图片来说明如果主元选取的不好,那么就会很囧。
可以看出,如果主元选的不好,那么快速排序的时间复杂度为O(N^2),很糟糕
1.3 常见的选择主元的方法
1.随机取 pivot?rand()函数不便宜啊!
2.取头、中、尾的中位数
例如 8、12、3的中位数就是8
下面给出中位数法的伪代码描述
ElementType Median3( ElementType A[], int Left, int Right )
{
int Center = ( Left + Right ) / 2;
if ( A[ Left ] > A[ Center ] )
Swap( &A[ Left ], &A[ Center ] );
if ( A[ Left ] > A[ Right ] )
Swap( &A[ Left ], &A[ Right ] );
if ( A[ Center ] > A[ Right ] )
Swap( &A[ Center ], &A[ Right ] );
/* A[ Left ] <= A[ Center ] <= A[ Right ] */
Swap( &A[ Center ], &A[ Right-1 ] ); /* 将pivot藏到右边 */
/* 只需要考虑 A[ Left+1 ] ... A[ Right–2 ] */
return A[ Right-1 ]; /* 返回 pivot */
}
1.4 子集划分算法
使用一幅图片来说明
如果有元素正好等于pivot怎么办?
1.停下来交换?
1.不理它,继续移动指针?
举一个极端的例子,如果,如果一个数组全是和主元相等,如果使用停下来交换,就会做无用的交换,如果 不理它,继续移动指针,那么i会一直移动到大于j,此时我们的主元就会在端点,那么所造成的影响就是时间复杂度为O(N^2)
所以我们选择 停下来交换
1.5快速排序的问题
1.用递归......
对小规模的数据(例如N不到100)可能还不如插入排序快
2.解决方案
当递归的数据规模充分小,则停止递归,直接调用简单排序(例如插入排序)
在程序中定义一个Cutoff的阈值 —— 课后去实践一下,比较不同的Cutoff对效率的影响
1.6快速排序的测试结果
阀值都取100的情况下
1.7 结果分析
对于不同的阀值,发现效率差距并不是很大。但是选择不同pivot,差距很大。从测试结果看
中位数效果最好,随机数次之,使用第一个元素作为pivot效果最差。所以今后尽量使用中位数方法。
1.8 快速排序代码
1 /* 2 * quickSort.c 3 * 4 * Created on: 2017年5月20日 5 * Author: ygh 6 */ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #define MAX_LENGTH 100000 11 typedef int elementType; 12 13 /* 14 * Swap two integer number value 15 */ 16 void swap(elementType *a, elementType *b) { 17 int temp = *b; 18 *b = *a; 19 *a = temp; 20 } 21 22 /* 23 * Print the array to console 24 * @param a A integer array need to sort 25 * @param n The length of the array 26 */ 27 void printArray(int a[], int n) { 28 int i; 29 for (i = 0; i < n; i++) { 30 if (i == n - 1) { 31 printf("%d", a[i]); 32 } else { 33 printf("%d ", a[i]); 34 } 35 } 36 printf("\n"); 37 } 38 39 /* 40 * Get input data from command 41 */ 42 void getInputData(elementType *a, int n) { 43 int i; 44 elementType x; 45 for (i = 0; i < n; i++) { 46 scanf("%d", &x); 47 a[i] = x; 48 } 49 } 50 51 /* 52 * Implement insertion sort. 53 *@param a A <code>elementType</code> array need to sort 54 *@param n The length of the array 55 */ 56 void insertion_sort(elementType a[], int n) { 57 int i, j; 58 elementType temp; 59 for (i = 1; i < n; i++) { 60 temp = a[i]; 61 for (j = i; j > 0 && a[j - 1] > temp; j--) { 62 a[j] = a[j - 1]; 63 } 64 a[j] = temp; 65 } 66 67 } 68 69 /* 70 *Get the pivot by get the median amount three number 71 */ 72 elementType getPivotByMedian3(elementType a[], int left, int right) { 73 int center = (left + right) / 2; 74 /* 75 * Let a[left]<= a[center] <= a[right] 76 */ 77 if (a[left] > a[center]) { 78 swap(&a[left], &a[center]); 79 } 80 81 if (a[left] > a[right]) { 82 swap(&a[left], &a[right]); 83 } 84 85 if (a[center] > a[right]) { 86 swap(&a[center], &a[right]); 87 } 88 89 /* 90 * We has known the a[right] greater than a[center] 91 * so we swap the a[center] and a[right-1],so we just 92 * consider from a[left+1] to a[right-2] when we divide sub-set 93 */ 94 swap(&a[center], &a[right - 1]); 95 return a[right - 1]; 96 97 } 98 99 elementType getPivotByRandom(elementType a[], int left, int right) { 100 int index = rand() % (right - left + 1) + left; 101 return index; 102 } 103 104 /* 105 * Implement quick sort,we get the pivot by the middle of three numbers 106 * @param a A <code>elementType</code> array need to sort 107 * @param left The starting index of sub-set 108 * @param right The finishing index of sub-set 109 * @param A cutoff to determine how many numbers rest we will 110 * use the insertion sort. 111 */ 112 void qSort(elementType a[], int left, int right, int cutoff) { 113 int low, high; 114 elementType pivot; 115 if (cutoff <= right - left) { 116 pivot = getPivotByMedian3(a, left, right); 117 low = left; 118 high = right - 1; 119 while (1) { 120 while (a[++low] < pivot) 121 ; 122 while (a[--high] > pivot) 123 ; 124 if (low < high) { 125 swap(&a[low], &a[high]); 126 } else { 127 break; 128 } 129 } 130 swap(&a[low], &a[right - 1]); 131 qSort(a, left, low - 1, cutoff); 132 qSort(a, low + 1, right, cutoff); 133 134 } else { 135 insertion_sort(a + left, right - left + 1); 136 } 137 } 138 139 /* 140 * Implement quick sort,we get the pivot by the middle of three numbers 141 * @param a A <code>elementType</code> array need to sort 142 * @param left The starting index of sub-set 143 * @param right The finishing index of sub-set 144 * @param A cutoff to determine how many numbers rest we will 145 * use the insertion sort. 146 */ 147 void qSortByRandom(elementType a[], int left, int right, int cutoff) { 148 int low, high, index; 149 elementType pivot; 150 if (cutoff <= right - left) { 151 index = getPivotByRandom(a, left, right); 152 swap(&a[left], &a[index]); 153 pivot = a[left]; 154 low = left; 155 high = right; 156 while (low < high) { 157 while (low < high && a[high] >= pivot) { 158 high--; 159 } 160 a[low] = a[high]; 161 while (low < high && a[low] <= pivot) { 162 low++; 163 } 164 a[high] = a[low]; 165 } 166 a[low] = pivot; 167 qSortByRandom(a, left, low - 1, cutoff); 168 qSortByRandom(a, low + 1, right, cutoff); 169 } else { 170 insertion_sort(a + left, right - left + 1); 171 } 172 } 173 174 /* 175 * Implement quick sort,we get the pivot by the middle of three numbers 176 * @param a A <code>elementType</code> array need to sort 177 * @param left The starting index of sub-set 178 * @param right The finishing index of sub-set 179 * @param A cutoff to determine how many numbers rest we will 180 * use the insertion sort. 181 */ 182 void qSortByFirstNum(elementType a[], int left, int right, int cutoff) { 183 int low, high; 184 elementType pivot; 185 if (cutoff <= right - left) { 186 pivot = a[left]; 187 low = left; 188 high = right; 189 while (low < high) { 190 while (low < high && a[high] >= pivot) { 191 high--; 192 } 193 a[low] = a[high]; 194 while (low < high && a[low] <= pivot) { 195 low++; 196 } 197 a[high] = a[low]; 198 } 199 a[low] = pivot; 200 qSortByFirstNum(a, left, low - 1, cutoff); 201 qSortByFirstNum(a, low + 1, right, cutoff); 202 } else { 203 insertion_sort(a + left, right - left + 1); 204 } 205 } 206 207 /* 208 * Implement sort unitized interface 209 * @param a A <code>elementType</code> array need to sort 210 * @param n The length of the array 211 */ 212 void quickSort(elementType a[], int n) { 213 // qSort(a, 0, n - 1, 100); 214 // qSortByRandom(a, 0, n - 1, 100); 215 qSortByFirstNum(a, 0, n - 1, 2); 216 } 217 218 219 220 int main() { 221 int a[MAX_LENGTH]; 222 int n; 223 scanf("%d", &n); 224 getInputData(a, n); 225 quickSort(a, n); 226 printArray(a, n); 227 return 0; 228 }
2 表排序
2.1概述
在我们之前学过的排序中,我们都是使用交换两个元素的位置来进行排序。可是如果现在的元素不是两个简单的数字,而是2G的视频,如果进行交换位置的排序,那么就要计算元素移动的时间。那么我们然后对这些元素进排序呢。
2.2 算法思想
下面有一组数据,里面的数据我们可以抽象是结构体存储。每个数据按照key去排序。但是结构体里面不仅仅有key,每个结构体还有2G的视频内容。那我们如何进行排序。例如下图:
那么如何在不进行移动元素的情况下,对数据按key进排序。我们在为数据增加一行指针数组,叫做表(table),来记录正确顺序的A的角标。初始化指针数组的值和A的角标对应。然后我们安装普通排序的方法(插入排序)对指针数组进排序。如,按照插入排序,第一趟比较f和d的大小 ,d<f,则把table的0角标元素往后面摞一位,然后在table的0角标放入1值。代表指向a[1].keytable的1角标存放0,代表指向a[0].key。然后下面按照插入排序进行对table的元素进排序。
下面使用一幅图片来说明:
2.3 物理排序
上面我们已经在逻辑上把数据排好序了,如果只需顺序输出,那么我只需要做A[table[0]],A[table[1]]… a[table[n-1]]即可。但是如果我们需要把把数据进行排序,让其逻辑上进行有序,那应该怎么做。
首先我们有一个定理:N个数字的排列由若干个独立的环组成
我们来看一下我们最终排序的结果:
由于进行元素的交换,则产生环路。位置和初始状态没有发生改变的独自成环。下面我们需要根据环来对物理数据进行排序。
首先建立一个临时的数据存储单元temp,用来存储临时的变量。我们从A[0]开始。temp=f,通过table[0]找到A[3],让A[0]=A[3],并更新table[0]=0;在通过A[3]的table[3]找到A[1],让A[3]=A[1],更新table[3]=3……
如何判断环结束table[i]==i
2.4 时间复杂度分析
最好情况:一开始有序,那么就不需要进行交换
我们知道,每一个环需要开辟一个temp数组,如果一个环中有T个元素,需要移动T+1次,多了两次temp的移进和移出。
那么最坏的情况是有N/2个环,每个环有2个元素,每个环需要移动3次。总共需移动(3N)/2次
T=O(mN).m为每个元素移动的时间,当元素的移动时间不能忽略时,就必须加上m
3 基数排序
3.1 桶排序
我们首先举一个例子:
3.2基数排序的算法思想
3.3 基数排序思想的应用
表排序的源代码
1 /* 2 * tableSort.c 3 * 4 * Created on: 2017年5月22日 5 * Author: ygh 6 */ 7 #include <stdio.h> 8 #include <stdlib.h> 9 #define MAX_LENGTH 100 10 11 typedef int contentType; 12 13 typedef struct node element; 14 typedef struct node { 15 char key; 16 contentType content; 17 } data[MAX_LENGTH]; 18 19 typedef struct node1 *ptrTable; 20 typedef struct node1 { 21 data d; 22 int table[MAX_LENGTH]; 23 }; 24 25 /* 26 * Create a empty table to store data 27 * @param n The length of the table 28 * @return ptrTable A point of structure of the table 29 */ 30 ptrTable createEmptyTable(int n) { 31 ptrTable table = (ptrTable) malloc(sizeof(struct node1)); 32 int i; 33 for (i = 0; i < n; i++) { 34 table->table[i] = i; 35 } 36 return table; 37 } 38 39 /* 40 * Insert a data to table 41 * @param table A point of structure of the table 42 * @param index The index of the element inserted 43 * @param key The key of the element inserted 44 * @param content The content of the element inserted 45 */ 46 void insertData(ptrTable table, int index, char key, contentType content) { 47 table->d[index].content = content; 48 table->d[index].key = key; 49 } 50 51 /* 52 * Implement table sort. 53 * Algorithms thoughts: 54 * 1.Because the data in <code>data</code> is too large,So we don't swap them 55 * 2.We use a table to record the data position,at the first time,the table's value is 56 * equal the index in the <code>data</code> 57 * 3. we sort data by key and record the sorted position by the table 58 * 4.When we need to access the table sorted,we just access data[table[i]] 59 * 60 * @param table A point of structure of the table 61 * @param n The length of the table 62 */ 63 void tableSort(ptrTable table, int n) { 64 int i, j; 65 char key; 66 int t; 67 for (i = 1; i < n; i++) { 68 key = table->d[i].key; 69 t = table->table[i]; 70 for (j = i; j > 0 && table->d[table->table[j - 1]].key > key; j--) { 71 table->table[j] = table->table[j - 1]; 72 } 73 table->table[j] = t; 74 } 75 } 76 77 /* 78 * Implement the data physical sort according the table 79 * @param table A point of structure of the table 80 * @param n The length of the table 81 * 82 */ 83 void physicalSort(ptrTable table, int n) { 84 int i, j; 85 int t; 86 element temp; 87 for (i = 0; i < n; i++) { 88 if (table->table[i] != i) { 89 temp = table->d[i]; 90 t = table->table[i]; 91 table->d[i] = table->d[t]; 92 table->table[i] = i; 93 j = t; 94 while (t != i) { 95 t = table->table[j]; 96 if (t == i) { 97 break; 98 } 99 table->d[j] = table->d[t]; 100 table->table[j] = j; 101 j = t; 102 } 103 table->d[j] = temp; 104 table->table[j] = j; 105 } else { 106 continue; 107 } 108 } 109 } 110 111 /* 112 * Print the table's content to console 113 * @param table A point of structure of the table 114 * @param n The length of the table 115 */ 116 void toStringTale(ptrTable table, int n) { 117 int i; 118 for (i = 0; i < n; i++) { 119 printf("key:%c,content:%d\n", table->d[table->table[i]].key, 120 table->d[table->table[i]].content); 121 } 122 } 123 124 int main() { 125 char arr[] = "fdcagbhe"; 126 int i; 127 int n = 8; 128 ptrTable table = createEmptyTable(n); 129 for (i = 0; i < n; i++) { 130 insertData(table, i, arr[i], i); 131 } 132 tableSort(table, n); 133 //toStringTale(table, n); 134 physicalSort(table, n); 135 toStringTale(table, n); 136 return 0; 137 }
表排序的测试结果:
1 key:a,content:3 2 key:b,content:5 3 key:c,content:2 4 key:d,content:1 5 key:e,content:7 6 key:f,content:0 7 key:g,content:4 8 key:h,content:6
基数排序LSD
1 /* 2 * radixSortLSD.c 3 * Implement radix sort of Least Significant Digit 4 * 5 * Created on: 2017年5月23日 6 * Author: ygh 7 */ 8 #include <stdio.h> 9 #include <stdlib.h> 10 11 #define MAX_LENGTH 10000 12 13 /* 14 *The quantity of the the keys of element 15 *For example 0-9999 have four keys 16 */ 17 #define MAX_DIGIT 6 18 /* 19 *The quantity of the bucket.In this case ,we sort integer number 20 *So the buckets is from 0 to 9 21 */ 22 #define RADIX 10 23 24 #define BEGIN_DIGIT 0 25 26 /* 27 * The type of the element type 28 */ 29 typedef int elementType; 30 31 /* 32 * Define a data structure for bucket node 33 */ 34 typedef struct node *ptrToNode; 35 typedef struct node { 36 /* 37 * The element type the bucket node store 38 */ 39 elementType key; 40 /* 41 * A next point to point next element 42 */ 43 ptrToNode next; 44 45 }; 46 47 /* 48 * Define a data structure for bucket head that 49 * store the head point and rear point for the elements 50 */ 51 typedef struct headNode { 52 ptrToNode head, rear; 53 }; 54 55 /* 56 * Define a array of headNode to store the all buckets 57 */ 58 typedef struct headNode bucket[RADIX]; 59 60 /* 61 * Get the digit by the current number and current needed digit 62 * @param x The current number 63 * @param d The current digit 64 * @return The digit needed 65 */ 66 int getDigit(elementType x, int d) { 67 int i; 68 int di; 69 for (i = 0; i < d; i++) { 70 di = x % RADIX; 71 x = x / RADIX; 72 } 73 return di; 74 } 75 76 void LSDRadixSort(elementType a[], int n) { 77 int d, di, i; 78 /* 79 * Define a bucket array to store all buckets 80 */ 81 bucket b; 82 83 /* 84 * Define three node point 85 * @param temp Store temporary node 86 * @param p A node point will be used when search 87 * @param list A node point to build elements list and recovery 88 * elements from finished sort 89 */ 90 ptrToNode temp, p, list; 91 92 /* 93 * Initialize each bucket head and rear into NULL 94 */ 95 for (i = BEGIN_DIGIT; i < RADIX; i++) { 96 b[i].head = b[i].rear = NULL; 97 } 98 99 /* 100 * Change array elements into list elements,but it is DESC 101 */ 102 for (i = 0; i < n; i++) { 103 temp = (ptrToNode) malloc(sizeof(struct node)); 104 temp->key = a[i]; 105 temp->next = list; 106 list = temp; 107 } 108 109 /* 110 * Do radix sort 111 */ 112 for (d = 1; d <= MAX_DIGIT; d++) { 113 p = list; 114 while (p) { 115 di = getDigit(p->key, d); 116 if (di < 0) { 117 di = di * (-1); 118 } 119 /* 120 * Delete this element from the list 121 */ 122 temp = p; 123 p = p->next; 124 temp->next = NULL; 125 if (b[di].head == NULL) { 126 b[di].head = b[di].rear = temp; 127 } else { 128 b[di].rear->next = temp; 129 b[di].rear = temp; 130 } 131 } 132 133 /* 134 * Recover the elements has been deal with,using 135 * the list to point the head 136 */ 137 list = NULL; 138 for (di = RADIX - 1; di >= BEGIN_DIGIT; di--) { 139 if (b[di].head) { 140 b[di].rear->next = list; 141 list = b[di].head; 142 /* 143 * Clear the head and rear 144 */ 145 b[di].rear = b[di].head = NULL; 146 } 147 } 148 } 149 150 /* 151 * Put sorted list data to array 152 */ 153 for (i = 0; i < n; i++) { 154 temp = list; 155 list = list->next; 156 a[i] = temp->key; 157 free(temp); 158 } 159 160 } 161 162 /* 163 * Print the array to console 164 * @param a A integer array need to sort 165 * @param n The length of the array 166 */ 167 void printArray(int a[], int n) { 168 int i; 169 for (i = 0; i < n; i++) { 170 if (i == n - 1) { 171 printf("%d", a[i]); 172 } else { 173 printf("%d ", a[i]); 174 } 175 } 176 printf("\n"); 177 } 178 179 /* 180 * Get input data from command 181 */ 182 void getInputData(elementType *a, int n) { 183 int i; 184 elementType x; 185 for (i = 0; i < n; i++) { 186 scanf("%d", &x); 187 a[i] = x; 188 } 189 } 190 191 /* 192 * Separate a array into positive array and negative array 193 * @param a A array store the positive number or negative number 194 * @param n The length of the a 195 * @param pL The length of the positive array 196 * @param pL The length of the negative array 197 */ 198 void separate(elementType *a, int n, int *pL, int *nL, 199 elementType positiveArr[], elementType negativeArr[]) { 200 int i; 201 for (i = 0; i < n; i++) { 202 if (a[i] < 0) { 203 negativeArr[(*nL)++] = a[i]; 204 } else { 205 positiveArr[(*pL)++] = a[i]; 206 } 207 } 208 } 209 210 /* 211 * Implement radix sort 212 */ 213 void radixSort(elementType a[], int n) { 214 int positiveArr[MAX_LENGTH]; 215 int negativeArr[MAX_LENGTH]; 216 int pL = 0, nL = 0, i, j; 217 separate(a, n, &pL, &nL, positiveArr, negativeArr); 218 LSDRadixSort(positiveArr, pL); 219 LSDRadixSort(negativeArr, nL); 220 i = nL - 1; 221 j = 0; 222 while (i >= 0) { 223 a[j] = negativeArr[i]; 224 i--; 225 j++; 226 } 227 i = 0; 228 while (i < pL) { 229 a[j] = positiveArr[i]; 230 i++; 231 j++; 232 } 233 234 } 235 236 int main() { 237 elementType a[MAX_LENGTH]; 238 int n; 239 scanf("%d", &n); 240 getInputData(a, n); 241 radixSort(a, n); 242 printArray(a, n); 243 return 0; 244 }
基数排序MSD
/* * radixSortMSD.c *Implement radix sort(Most Significant Digit) * Created on: 2017年5月24日 * Author: ygh */ #include <stdio.h> #include <stdlib.h> #define MAX_LENGTH 100000 #define RADIX 10 #define MAX_DIGIT 3 #define BEGIN_DIGIT 0 /* * Define element type the array or list store */ typedef int elementType; /* * Define a list to store elememts from array */ typedef struct node *ptrToNode; typedef struct node { elementType key; ptrToNode next; }; /* * Define a bucket to point the each bucket list head and rear */ typedef struct headNode { ptrToNode head, rear; }; /* *Define a bucket array to store all buckets */ typedef struct headNode bucket[RADIX]; /* * Get the current number digit by current digit needed * @param x The number current need to sort * @param d The digit current need to get * @return A current digit of this number */ int getDigit(elementType x, int d) { int i; int de; for (i = 0; i < d; i++) { de = x % RADIX; x = x / RADIX; } return de; } /* * Implement radix sort by MSD,we will recursive to implement it */ void radixSortMSD(elementType a[], int left, int right, int d) { int di, i, j; /* * Define three point of the list * @param p The point is used for searching * @param temp The point is used for temporary store * @param list The point is used for store all elements */ ptrToNode p, temp, list = NULL; /* * Define a bucket array for all buckets */ bucket b; /* * recursive end conditional */ if (d == 0) { return; } /* * Initialize all bucket,let head and rear get NULL */ for (i = BEGIN_DIGIT; i < RADIX; i++) { b[i].head = b[i].rear = NULL; } /* * Change array storing into list storing,it make the data * easily to be deal with */ list = NULL; for (i = left; i <= right; i++) { temp = (ptrToNode) malloc(sizeof(struct node)); temp->key = a[i]; temp->next = list; list = temp; } p = list; /* * Get digit from current number and deal with them */ while (p) { di = getDigit(p->key, d); temp = p; p = p->next; temp->next = NULL; if (b[di].head == NULL) { b[di].rear = temp; b[di].head=temp; } else { temp->next = b[di].head; b[di].head = temp; } } /* * recover elements from bucket */ i = j = left; for (di = 0; di < RADIX; di++) { if (b[di].head) { p = b[di].head; while (p) { temp = p; p = p->next; a[j++] = temp->key; free(temp); } /* *recursive caller this method */ radixSortMSD(a, i, j - 1, d - 1); i = j; } } } /* * Implement radix sort */ void radixSort(elementType a[], int n) { radixSortMSD(a, 0, n - 1, MAX_DIGIT); } /* * Print the array to console * @param a A integer array need to sort * @param n The length of the array */ void printArray(int a[], int n) { int i; for (i = 0; i < n; i++) { if (i == n - 1) { printf("%d", a[i]); } else { printf("%d ", a[i]); } } printf("\n"); } /* * Get input data from command */ void getInputData(elementType *a, int n) { int i; elementType x; for (i = 0; i < n; i++) { scanf("%d", &x); a[i] = x; } } int main() { elementType a[MAX_LENGTH]; int n; scanf("%d", &n); getInputData(a, n); radixSort(a, n); printArray(a, n); printf("just test"); return 0; }
练习题:
10-排序4 统计工龄 (20分)
给定公司NNN名员工的工龄,要求按工龄增序输出每个工龄段有多少员工。
输入格式:
输入首先给出正整数NNN(≤105\le 10^5≤105),即员工总人数;随后给出NNN个整数,即每个员工的工龄,范围在[0, 50]。
输出格式:
按工龄的递增顺序输出每个工龄的员工个数,格式为:“工龄:人数”。每项占一行。如果人数为0则不输出该项。
输入样例:
8
10 2 0 5 7 2 5 2
输出样例:
0:1
2:3
5:2
7:1
10:1
时间限制:400ms
内存限制:64MB
代码长度限制:16kB
判题程序:系统默认
作者:陈越
单位:浙江大学
题目判定
解题程序
编译器:*
程序代码:*
提交
我使用了归并排序为基础,下面是代码的实现
1 /* 2 * countAge.c 3 * 4 * Created on: 2017年5月24日 5 * Author: ygh 6 */ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #define MAX_LENGTH 100000 11 12 typedef int elementType; 13 14 /* 15 * Swap two integer number value 16 */ 17 void swap(elementType *a, elementType *b) { 18 int temp = *b; 19 *b = *a; 20 *a = temp; 21 } 22 23 /* 24 * Merge sub-sequence to original array. 25 * @param a original <code>elementType</code> array to store the elements 26 * @param tmpA temporary <code>elementType</code> array to store the temporary elements 27 * @param l The start index of left sub-sequence 28 * @param r The start index of left sub-sequence 29 * @param rightEnd The end index of left sub-sequence 30 */ 31 void merge(elementType a[], elementType tmpA[], int l, int r, int rightEnd) { 32 /* 33 * lefeEnd is the r-1,the sub-sequence is adjacent 34 */ 35 int leftEnd = r - 1; 36 /* 37 * tmp is the counter of the <code>tmpA</code> 38 * we should let <code>tmpA</code> index corresponding original array 39 */ 40 int tmp = l; 41 /* 42 * Record the quantity of the all elements 43 */ 44 int numElements = rightEnd - l + 1; 45 int i; 46 while (l <= leftEnd && r <= rightEnd) { 47 if (a[l] <= a[r]) { 48 tmpA[tmp++] = a[l++]; 49 } else { 50 tmpA[tmp++] = a[r++]; 51 } 52 } 53 while (l <= leftEnd) { 54 tmpA[tmp++] = a[l++]; 55 } 56 while (r <= rightEnd) { 57 tmpA[tmp++] = a[r++]; 58 } 59 60 /* 61 * Put <code>tmpA</code> elements into the original array 62 */ 63 for (i = 0; i < numElements; i++, rightEnd--) { 64 a[rightEnd] = tmpA[rightEnd]; 65 } 66 } 67 68 /* 69 * Implement the merge sort 70 * @param a original <code>elementType</code> array to store the elements 71 * @param tmpA temporary <code>elementType</code> array to store the temporary elements 72 * @param l The start index of the array which need to sort 73 * @param rightEnd The end index of the array which need to sort 74 */ 75 void mergetSortRecursive(elementType a[], elementType tmpA[], int l, 76 int rightEnd) { 77 int center; 78 if (l < rightEnd) { 79 center = (l + rightEnd) / 2; 80 mergetSortRecursive(a, tmpA, l, center); 81 mergetSortRecursive(a, tmpA, center + 1, rightEnd); 82 merge(a, tmpA, l, center + 1, rightEnd); 83 } 84 } 85 86 /* 87 * Implement merge sort 88 * @param a A integer array need to sort 89 * @param n The length of the array 90 */ 91 void merger_sortRecursive(elementType a[], int n) { 92 elementType *tmpA; 93 tmpA = malloc(n * sizeof(elementType)); 94 if (tmpA != NULL) { 95 mergetSortRecursive(a, tmpA, 0, n - 1); 96 free(tmpA); 97 } else { 98 printf("no enough space to apply for temporary array"); 99 } 100 } 101 102 /* 103 *merge ordered sub-sequence 104 * @param a original <code>elementType</code> array to store the elements 105 * @param tmpA temporary <code>elementType</code> array to store the temporary elements 106 * @param n The length of the a 107 * @param the ordered current sub-sequence length 108 */ 109 void mergerPass(elementType a[], elementType tmpA[], int n, int lenth) { 110 int i, j; 111 /* 112 * The loop will stop when meet the last two ordered sub-sequence 113 * The rest may be two sub-sequence of one sub-sequence 114 */ 115 for (i = 0; i <= n - 2 * lenth; i += lenth * 2) { 116 merge(a, tmpA, i, i + lenth, i + 2 * lenth - 1); 117 } 118 /* 119 *If the rest of is two sub-sequence 120 */ 121 if (i + lenth < n) { 122 merge(a, tmpA, i, i + lenth, n - 1); 123 } else { 124 for (j = i; j < n; j++) 125 tmpA[j] = a[j]; 126 } 127 } 128 129 /* 130 * Use loop method to implement the merge sort 131 * @param a A integer array need to sort 132 * @param n The length of the array 133 */ 134 void merger_SortLoop(elementType a[], int n) { 135 int length; 136 elementType *tmpA; 137 length = 1; 138 tmpA = malloc(n * sizeof(elementType)); 139 if (tmpA != NULL) { 140 while (length < n) { 141 /* 142 * merge ordered sub-sequence into <code>tmpA</code> 143 */ 144 mergerPass(a, tmpA, n, length); 145 length *= 2; 146 /* 147 * merge ordered sub-sequence from <code>tmpA</code> into <code>a</code> 148 */ 149 mergerPass(tmpA, a, n, length); 150 length *= 2; 151 } 152 free(tmpA); 153 } else { 154 printf("no enough to apply for temporary array"); 155 } 156 } 157 158 /* 159 * Print the array to console 160 * @param a A integer array need to sort 161 * @param n The length of the array 162 */ 163 void printArray(int a[], int n) { 164 int i; 165 for (i = 0; i < n; i++) { 166 if (i == n - 1) { 167 printf("%d", a[i]); 168 } else { 169 printf("%d ", a[i]); 170 } 171 } 172 printf("\n"); 173 } 174 175 /* 176 * Get input data from command 177 */ 178 void getInputData(elementType *a, int n) { 179 int i; 180 elementType x; 181 for (i = 0; i < n; i++) { 182 scanf("%d", &x); 183 a[i] = x; 184 } 185 } 186 187 /* 188 * Count age and print them to console 189 */ 190 void countAge(elementType a[], int n) { 191 int i; 192 int key = a[0]; 193 int counter = 1; 194 for (i = 1; i < n; i++) { 195 if (a[i] == key) { 196 counter++; 197 } else { 198 printf("%d:%d\n",key,counter); 199 key = a[i]; 200 counter=1; 201 } 202 } 203 printf("%d:%d\n",key,counter); 204 } 205 206 int main() { 207 int a[MAX_LENGTH]; 208 int n; 209 scanf("%d", &n); 210 getInputData(a, n); 211 merger_SortLoop(a, n); 212 countAge(a, n); 213 return 0; 214 }
4 练习
4.1 Sort with Swap(0, i)
Given
any permutation of the numbers {0, 1, 2,..., N−1}, it is easy to
sort them in increasing order. But what if Swap(0,
*)
is the ONLY operation that is allowed to use? For example,
to sort {4, 0, 2, 1, 3} we may apply the swap operations in the
following way:
Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}
Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.
Input Specification:
Each input file contains one test case, which gives a positive N (≤105) followed by a permutation sequence of {0, 1, ..., N−1}. All the numbers in a line are separated by a space.
Output Specification:
For each case, simply print in a line the minimum number of swaps need to sort the given permutation.
Sample Input:
10
3 5 7 2 6 4 9 0 8 1
Sample Output:
9
-
时间限制:400ms
-
内存限制:64MB
-
代码长度限制:16kB
-
判题程序:系统默认
-
作者:陈越
-
单位:浙江大学
4.2 算法思想
这道题目要求我们和零交换来实现排序,那么我们联想到之前的表排序,如何对下表实现物理排序,那么需要在每个环中进行位置的交换。在环中进行位置交换的时候,我们会先使用一个临时的空间去存放第一个需要交换的元素,然后让第一个元素有一个空位,然后把下一个元素移动到第一个元素的位置。直到环中的最后一个元素,把临时空间中的元素移动到最后一个元素的位置。根据此算法思想,我们可以衍生此题的解法。我们把每次移动的空闲位置区域看做是0,然后每次移动元素时,就相当和0进行交换。如果有的环不包括0,怎么办?我们可以把0换到环里,然后进行移动。
4.3 环的分类
4.4 程序的实现
我们知道0-N个元素有序排列应该这样
下标 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A[] |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
但是现在题目所给的序列为这样
下标 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A[] |
3 |
5 |
7 |
2 |
6 |
4 |
9 |
0 |
8 |
1 |
我们需要建立如下一个数组T[],来记录当前元素存储的位置,例如A[0]应该存放0元素,但是我们不能遍历一遍A[]去查找0元素,这样太慢了。我们在插入0时就应该记录0所在的位置。例如插入0的时候,i为7,我们需要记录T[A[i]]=i。这样我们就可以很快的通过A[0]=0=A[T[0]]
下面我们构造T[]数组
下标 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
T[] |
7 |
9 |
3 |
0 |
5 |
1 |
4 |
2 |
8 |
6 |
这样我们可以建立一个环了。
下面是代码:代码可以通过PTA所有的测试点
1 /* 2 * SortwithSwap.c 3 * 4 * Created on: 2017年5月25日 5 * Author: ygh 6 */ 7 #include <stdio.h> 8 #include <stdlib.h> 9 10 #define MAX_LENGTH 100000 11 12 typedef int elementType; 13 /* 14 * Define a data structure to store data 15 */ 16 typedef struct dataNode *ptrToData; 17 typedef struct dataNode { 18 elementType a[MAX_LENGTH]; 19 int table[MAX_LENGTH]; 20 }; 21 22 /* 23 * Create empty array point 24 */ 25 ptrToData createEmptyData() { 26 ptrToData data = (ptrToData) malloc(sizeof(struct dataNode)); 27 return data; 28 } 29 30 /* 31 * Insert element to data and record the index 32 * @param data A point to point the data 33 * @param n The length of the arrays 34 */ 35 void insertElement(ptrToData data, int n) { 36 elementType x; 37 int i; 38 for (i = 0; i < n; i++) { 39 scanf("%d", &x); 40 data->a[i] = x; 41 data->table[x] = i; 42 } 43 } 44 45 /* 46 *Calculate the swap times.when we access next element by 47 *circle, we let the counter increase one. If the circle contain zero,counter decrease one 48 *otherwise counter increase one. 49 * @param data A point to point the data 50 * @param n The length of the arrays 51 * @param m The counter of the multiple circle 52 * @param s The counter of the single circle 53 */ 54 int calculateSwapTimes(ptrToData data, int n) { 55 /* 56 * @param key The index to record the next element by circle 57 * @param j The index the current element 58 */ 59 int i,key,j; 60 /* 61 * record the all swap 62 */ 63 int counter=0; 64 for (i = 0; i < n; i++) { 65 if(i==data->table[i]){ 66 continue; 67 }else{ 68 key = data->table[i]; 69 counter++; 70 data->table[i]=i; 71 j=key; 72 while(key!=i){ 73 key=data->table[j]; 74 counter++; 75 data->table[j]=j; 76 j = key; 77 } 78 if(i==0){ 79 counter--; 80 }else{ 81 counter++; 82 } 83 } 84 } 85 return counter; 86 } 87 88 void toString(ptrToData data, int n) { 89 int i; 90 for (i = 0; i < n; i++) { 91 printf("%d ", data->a[data->table[i]]); 92 } 93 } 94 95 int main() { 96 ptrToData data = createEmptyData(); 97 int n,count; 98 scanf("%d", &n); 99 insertElement(data, n); 100 count = calculateSwapTimes(data, n); 101 printf("%d",count); 102 return 0; 103 }