zoukankan      html  css  js  c++  java
  • 算法拾遗系列-常用排序算法合集

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

    参考书籍:算法导论

  • 相关阅读:
    windows 设置nginx开机自启动
    vue js中解决二进制转图片显示问题
    oracle 各种问题
    Nginx安装及配置详解包括windows linux 环境
    AOP-切面是如何织入到目标对象中的
    AOP-通知-笔记
    AOP-方法拦截器-笔记
    JdkDynamicAopProxy-笔记
    Joinpoint继承体系-笔记
    AOP-Pointcut-笔记
  • 原文地址:https://www.cnblogs.com/lxiao/p/4357536.html
Copyright © 2011-2022 走看看