算法拾遗系列-常用排序算法合集

    前几天要参加去哪儿的实习生笔试,所有又把集中常用也会常考的排序算法又拿出来温习了一遍。发现很长时间练习,还是会很生疏。这些算法说起来好像都能讲出基本的步骤,但真的写起来发现会出现很多纰漏。边界条件什么的常常考虑不周全,要能真正写出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  阅读(256)  评论(0编辑  收藏  举报

导航