算法拾遗系列-常用排序算法合集
前几天要参加去哪儿的实习生笔试,所有又把集中常用也会常考的排序算法又拿出来温习了一遍。发现很长时间练习,还是会很生疏。这些算法说起来好像都能讲出基本的步骤,但真的写起来发现会出现很多纰漏。边界条件什么的常常考虑不周全,要能真正写出bug-free的程序还需要不断训练,正应了那句老话-“talk is cheap,show me the code!”,IT行业,code才是硬通货。
转入正题,常用的几种排序算法中,需要不停对比相邻元素的算法基本上时间复杂度都是O(n2),而用到了分治方法的基本都是O(nlogn)。
下面是代码,编译通过,结果也都正确。
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 6 template<typename T> 7 void printArray(T *arr,int n){ 8 for (int i=0;i<n;i++) 9 cout<<arr[i]<<" "; 10 cout<<endl; 11 } 12 13 //二分搜索 14 //T(n)=O(nlogn) 15 int binarySearch(int *arr,int beg,int end,int key){ 16 if (end >= beg){ 17 int mid = (beg+end)/2; 18 if (arr[mid] == key) 19 return mid; 20 if (arr[mid] <key ) 21 return binarySearch(arr,mid+1,end,key); 22 else 23 return binarySearch(arr,beg,mid-1,key); 24 } 25 return -1; 26 } 27 28 template<typename T> 29 void swap(T *a,T *b){ 30 T tmp = *a; 31 *a = *b; 32 *b = tmp; 33 } 34 35 //选择排序 36 /* 37 每次迭代都将剩下未排序序列中最小元素 38 放在未排序序列开始处 39 T(n)=O(n2) 40 */ 41 void SelectionSort(int *arr,int n){ 42 int i,j,min; 43 for (i=0;i<n-1;i++){ 44 min = i; 45 for (j = i+1;j<n;j++){ 46 if (arr[j]<arr[min]) 47 min = j; 48 } 49 swap(&arr[min],&arr[i]); 50 } 51 } 52 53 //冒泡排序 54 /* 55 算法每趟都交换相邻元素(如果它们无序),使最大元素位于最右侧 56 并在下次扫描中排出该元素 57 T(n)=O(n2) 58 */ 59 void BubbleSort(int *arr,int n){ 60 for (int i=0;i<n;i++){ 61 for (int j=0;j<n-i-1;j++) 62 if (arr[j]>arr[j+1]) 63 swap(&arr[j],&arr[j+1]); 64 } 65 } 66 67 //插入排序 68 /* 69 算法就像打牌每次抽出一张牌,在左边找好位置并插入 70 T(n)=O(n2) 71 */ 72 void InsertionSort(int *arr,int n){ 73 int i,j; 74 for (i=1;i<n;i++){ 75 int tmp = arr[i]; 76 for (j=i-1;j>=0 && arr[j]>tmp;j--) 77 arr[j+1] = arr[j]; 78 arr[j+1] = tmp; 79 } 80 } 81 82 //合并 排序 83 /* 84 算法将数组分为两半,递归调用合并排序, 85 最后将两半排好序的数组再次合并 86 T(n)=O(nlogn) 87 */ 88 void merge(int *arr,int beg,int mid,int end){ 89 int n1 = mid - beg+1; 90 int n2 = end - mid; 91 92 int *a1 = new int[n1]; 93 int *a2 = new int[n2]; 94 95 for (int i=0;i<n1;i++) 96 a1[i] = arr[beg+i]; 97 for (int i=0;i<n2;i++) 98 a2[i] = arr[mid+1+i]; 99 100 int i=0,j=0,k=beg; 101 while (i<n1 && j<n2){ 102 if (a1[i] <= a2[j]){ 103 arr[k] = a1[i]; 104 ++i; 105 } 106 else{ 107 arr[k] = a2[j]; 108 ++j; 109 } 110 ++k; 111 } 112 113 while(i < n1){ 114 arr[k] = a1[i]; 115 ++i; 116 ++k; 117 } 118 119 while(j < n2){ 120 arr[k] = a2[j]; 121 ++j; 122 ++k; 123 } 124 } 125 126 void MergeSort(int *arr,int beg,int end){ 127 if (beg < end){ 128 int mid = (beg+end)/2; 129 MergeSort(arr,beg,mid); 130 MergeSort(arr,mid+1,end); 131 merge(arr,beg,mid,end); 132 } 133 } 134 135 //堆排序 136 /* 137 建一个最小堆,则数组就是有序的 138 本算法建的是最大堆,因此最后还要对数组做堆有序处理 139 T(n)=O(nlogn) 140 */ 141 typedef struct Heap{ 142 int size; 143 int *arr; 144 }Heap; 145 146 //维护最大堆有序 147 /* 148 我们一开始就假定根节点为LEFT(i)和RIGHT(i)的二叉堆都是最大堆。 149 当maxheap[i]的值比其子节点的值小时, 150 maxHeapify通过让maxheap[i]的值在最大堆中逐级下降, 151 使得以i为根的子树保持最大堆有序性 152 */ 153 void maxHeapify(Heap* maxheap,int idx){ 154 int left = (idx<<1)+1; 155 int right = (idx+1)<<1; 156 int largest = idx; 157 if (left < maxheap->size && maxheap->arr[left] > maxheap->arr[largest]) 158 largest = left; 159 if (right < maxheap->size && maxheap->arr[right] > maxheap->arr[largest]) 160 largest = right; 161 if (largest != idx){ 162 swap(&maxheap->arr[largest],&maxheap->arr[idx]); 163 maxHeapify(maxheap,largest);//percolate down 164 } 165 } 166 167 Heap* createMaxHeap(int *arr,int n){ 168 int i; 169 Heap* maxheap = (Heap*)malloc(sizeof(struct Heap)); 170 maxheap->size = n; 171 maxheap->arr = arr; 172 173 //堆有序操作 174 for (int i=(maxheap->size-2)/2;i>=0;--i) 175 maxHeapify(maxheap,i); 176 return maxheap; 177 } 178 179 void HeapSort(int *arr,int n){ 180 Heap* maxheap = createMaxHeap(arr,n); 181 while (maxheap->size >1){ 182 swap(&maxheap->arr[0],&maxheap->arr[maxheap->size-1]); 183 --maxheap->size; 184 //从根节点再次对整个堆进行堆有序操作 185 maxHeapify(maxheap,0); 186 } 187 } 188 189 190 //快排 191 /* 192 选取一个哨兵元素pivot,使数组中所有小于pivot的元素位于pivot左边 193 所有大于pivot的元素位于pivot右边 194 T(n)=O(nlogn) 195 worst situation consume O(n2) 196 */ 197 int Partition(int *arr,int beg,int end){ 198 //选择最后一个元素的中值为pivot 199 int pivot = arr[end]; 200 int i= beg; 201 int j= end-1; 202 while (i < j){ 203 if (arr[i] <= pivot){ 204 ++i; 205 continue; 206 } 207 if (arr[j] >= pivot){ 208 --j; 209 continue; 210 } 211 swap(&arr[i],&arr[j]); 212 ++i; 213 --j; 214 } 215 swap(&arr[j],&arr[end]); 216 return j; 217 } 218 219 void QuickSort(int *arr,int beg,int end){ 220 if (beg < end){ 221 int p = Partition(arr,beg,end); 222 QuickSort(arr,beg,p-1); 223 QuickSort(arr,p+1,end); 224 } 225 } 226 227 //桶排 228 /* 229 假设输入序列服从均匀分布平均情况下T(n)=O(n) 230 将【0,1)区间划分为n个大小相同子区间(bucket),将n个输入数分别放到对应桶中, 231 然后先对各个桶中数据进行排序,再遍历各个桶,按次序列出各个桶中元素即可 232 */ 233 void BucketSort(float *arr,int n){ 234 //buckets 235 vector<vector<float> > buckets(n); 236 for (int i=0;i<n;i++){ 237 int bi = arr[i]*n;// 238 buckets[bi].push_back(arr[i]); 239 } 240 for (int i=0;i<n;i++) 241 sort(buckets[i].begin(),buckets[i].end()); 242 int idx = 0; 243 for (int i=0;i<n;i++) 244 for (int j=0;j<buckets[i].size();j++) 245 arr[idx++] = buckets[i][j]; 246 247 } 248 249 //希尔排序 250 /* 251 希尔排序是插入排序的变种 252 有间隔的进行插入排序 253 */ 254 void ShellSort(int *arr,int n){ 255 for (int gap=n/2;gap>0;gap /= 2){ 256 for (int i=gap;i<n;i += 1){ 257 int tmp = arr[i]; 258 int j; 259 for (j=i;j>=gap && arr[j-gap] > tmp;j -= gap) 260 arr[j] = arr[j-gap]; 261 arr[j] = tmp; 262 } 263 } 264 } 265 266 int main() 267 { 268 int arr1[10] = {10,5,2,9,3,7,8,6,-1,4}; 269 cout<<"Selection sort:"; 270 SelectionSort(arr1,10); 271 printArray(arr1,10); 272 int idx = binarySearch(arr1,0,9,4); 273 if (idx == -1) 274 cout<<"Couldn't find..."<<endl; 275 else 276 cout<<"Find 4 in index: "<<idx<<endl; 277 278 cout<<"Bubble sort:"; 279 int arr2[10] = {10,5,2,9,3,7,8,6,-1,4}; 280 BubbleSort(arr2,10); 281 printArray(arr2,10); 282 283 cout<<"InsertitionSort: "; 284 int arr3[10] = {10,5,2,9,3,7,8,6,-1,4}; 285 InsertionSort(arr3,10); 286 printArray(arr3,10); 287 288 cout<<"MergeSort: "; 289 int arr4[10] = {10,5,2,9,3,7,8,6,-1,4}; 290 MergeSort(arr4,0,9); 291 printArray(arr4,10); 292 293 cout<<"HeapSort: "; 294 int arr5[] = {10,5,2,9,3,7,8,6,-1,4}; 295 int n5 = sizeof(arr5)/sizeof(arr5[0]); 296 HeapSort(arr5,n5); 297 printArray(arr5,n5); 298 299 cout<<"QuickSort: "; 300 int arr6[10] = {10,5,2,9,3,7,8,6,-1,4}; 301 QuickSort(arr6,0,9); 302 printArray(arr6,10); 303 304 cout<<"BucketSort: "; 305 float arr7[10] = {0.12,0.29,0.89,0.31,0.10,0.49,0.99,0.60,0.08,0.7}; 306 BucketSort(arr7,10); 307 printArray(arr7,10); 308 309 cout<<"ShellSort: "; 310 int arr8[10] = {10,5,2,9,3,7,8,6,-1,4}; 311 ShellSort(arr8,10); 312 printArray(arr8,10); 313 return 0; 314 }
注释基本上都能解释算法的基本思路,不懂得可以看以下算法导论。
运行结果如下:
代码参考:www.geeksforgeeks.org
参考书籍:算法导论
posted on 2015-03-22 16:32 lxiao_socool 阅读(258) 评论(0) 编辑 收藏 举报