本辑将会对笔试面试最常涉及到的12种排序算法(包括插入排序、二分插入排序、希尔排序、选择排序、冒泡排序、鸡尾酒排序、快速排序、堆排序、归并排序、桶排序、计数排序和基数排序)进行详解。每一种算法都有基本介绍、算法原理分析、图解演示、算法代码、笔试面试重点分析、笔试面试题等板块。
一、插入排序
1)算法简介
       插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
2)算法描述和分析
一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
1、从第一个元素开始,该元素可以认为已经被排序
2、取出下一个元素,在已经排序的元素序列中从后向前扫描
3、如果该元素(已排序)大于新元素,将该元素移到下一位置
4、重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5、将新元素插入到该位置后
6、重复步骤2~5
如果目标是把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。
最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。
最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较操作的次数减去(n-1)次。
平均来说插入排序算法复杂度为O(n^2)。
因而,插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序(通常为8个或以下)。
3)算法图解
4)算法代码
// 插入排序(直接,折半,路插入,表插入)
// 依次取出便利每一项 将每一项temp=a[j]和其之前的数进行比较,如果发现了比自己大的数 就将其放在当前j的位置 同时j--,继续用temp和之前的数进行比较,直到没有比自己大的数时结束。
// 直接插入排序  
void insertSort(int *a,int size)  
{  
    if(size<2)  
        return;  
    int temp;  
    int j;  
    for(int i=1;i<size;i++)  
    {  
        temp=a[i];  
        for( j=i;j>0&&temp<a[j-1];j--)  
        {  
              a[j]=a[j-1];  
        }  
        a[j]=temp;  
    }  
    print(a,size);  
} 
// 折半插入排序:
// 折半插入排序(binary insertion sort)是对插入排序算法的一种改进,由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
// 折半插入排序算法的具体操作为:在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素小,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。
void binaryInsertSort(int *a,int size)  
{  
    int low,high,m,temp,j;  
    for (int i=1;i<size;++i){  
       temp=a[i];  
       low=0;  
       high=i-1;  
      /* if(a[i]>a[i-1])   //这句话可以稍微优化一下下速度 不影响结果 
           continue;*/  
       while (low<=high){  
         m=(low+high)/2;  
         if (temp<=a[m])  
             high=m-1;   //当程序跳出时 high指向的其实并不是 >=temp的值的位置 而是>=temp的值的左边的位置 所以....  
         else    
             low=m+1;  
       }  
       for( j=i;j>high+1;--j)        //所以 这里的high要加一哇   
           a[j]=a[j-1];  
       a[j]=temp;  
     }  
    print(a,size);  
}  
5)考察点,重点和频度分析
把插入排序放在第一个的原因是因为其出现的频度不高,尤其是这里提到的直接排序算法,基本在笔试的选择填空问时间空间复杂度的时候才可能出现。毕竟排序速度比较慢,因此算法大题中考察的次数比较比较少。
6)笔试面试例题
例题1
请写出链表的插入排序程序
template<typename T>  
struct list_node  
{  
    struct list_node<T> *next;  
    T value;  
};  
template<typename T>  
struct _list  
{  
    struct list_node<T> *head;  
    int size;  
};  
template<typename T>  
void SortLink(struct _list<T> * link) {  
    struct list_node<T> *pHead,*pRear,*p,*tp;  
    if (!link) return;  
    for (pHead=link->head,pRear=0;pHead;pHead=pHead->next) {  
        for (tp=pHead,p=pHead->next;p;tp=p,p=p->next)  
            if (pHead->value>=p->value)  
                tp->next=p->next,p->next=pHead,pHead=p,p=tp;  
        if (!pRear) link->head=pHead;  
        else pRear->next=pHead;  
        pRear=pHead;  
    }  
}  
void BinInsertSort(int a[], int n)   
{   
        int key, left, right, middle;   
        for (int i=1; i<n; i++)   
        {   
                key = a[i];   
                left = 0;   
                right = i-1;   
                while (left<=right)   
                {   
                        middle = (left+right)/2;   
                        if (a[middle]>key)   
                                right = middle-1;   
                        else   
                                left = middle+1;   
                }   
                   
                for(int j=i-1; j>=left; j--)   
                {   
                        a[j+1] = a[j];   
                }   
                   
                a[left] = key;          
        }   
}   5)考察点,重点和频度分析
#include <stdio.h>  
   
int main()  
{  
     const int n = 5;  
     int i, j, temp;   
     int gap = 0;  
     int a[] = {5, 4, 3, 2, 1};   
     while (gap<=n)  
     {  
          gap = gap * 3 + 1;  
     }   
     while (gap > 0)   
     {  
         for ( i = gap; i < n; i++ )  
         {  
             j = i - gap;  
             temp = a[i];               
             while (( j >= 0 ) && ( a[j] > temp ))  
             {  
                 a[j + gap] = a[j];  
                 j = j - gap;  
             }  
             a[j + gap] = temp;  
         }  
         gap = ( gap - 1 ) / 3;  
     }      
 }  5)考察点,重点和频度分析最差时间复杂度О(n^2)最优时间复杂度О(n^2)平均时间复杂度О(n^2)最差空间复杂度О(n) total, O(1)
void selection_sort(int *a, int len)  
{  
    register int i, j, min, t;  
    for(i = 0; i < len - 1; i ++)  
    {  
        min = i;  
        //查找最小值  
        for(j = i + 1; j < len; j ++)  
            if(a[min] > a[j])  
                min = j;  
        //交换  
        if(min != i)  
        {  
            t = a[min];  
            a[min] = a[i];  
            a[i] = t;  
        }  
    }  
}  5)考察点,重点和频度分析#include <stdio.h> 
void bubbleSort(int arr[], int count) 
{ 
int i = count, j; 
int temp; 
while(i > 0) 
{ 
for(j = 0; j < i - 1; j++) 
{ 
if(arr[j] > arr[j + 1]) 
{ temp = arr[j]; 
arr[j] = arr[j + 1]; 
arr[j + 1] = temp; 
} 
} 
i--; 
} 
} 
int main() 
{ 
//测试数据 
int arr[] = {5, 4, 1, 3, 6}; 
//冒泡排序 
bubbleSort(arr, 5); 
//打印排序结果 
int i; 
for(i = 0; i < 5; i++) 
printf("%4d", arr[i]); 
} 5)考察点,重点和频度分析#include <stdio.h> 
#include <string.h> 
//题目以及要求:把一个字符串的大写字母放到字符串的后面, 
//各个字符的相对位置不变,不能申请额外的空间。 
//判断是不是大写字母 
int isUpperAlpha(char c){ 
if(c >= 'A' && c <= 'Z'){ 
return 1; 
} 
return 0; 
} 
//交换两个字母 
void swap(char *a, char *b){ 
char temp = *a; 
*a = *b; 
*b = temp; 
} 
char * mySort(char *arr, int len){ 
if(arr == NULL || len <= 0){ 
return NULL; 
} 
int i = 0, j = 0, k = 0; 
for(i = 0; i < len; i++){ 
for(j = len - 1 - i; j >= 0; j--){ 
if(isUpperAlpha(arr[j])){ 
for(k = j; k < len - i - 1; k++){ 
swap(&arr[k], &arr[k + 1]); 
} 
break; 
} 
//遍历完了字符数组,但是没发现大写字母,所以没必要再遍历下去 
if(j == 0 && !isUpperAlpha(arr[j])){ 
//结束; 
return arr; 
} 
} 
} 
//over: 
return arr; 
} 
int main(){ 
char arr[] = "aaaaaaaaaaaaaaaaaaaaaaaAbcAdeBbDc"; 
printf("%s\n", mySort(arr, strlen(arr))); 
return 0; 
} 解法二#include <stdio.h> 
#include <string.h> 
//判断是不是大写字母 
int isUpperAlpha(char c){ 
if(c >= 'A' && c <= 'Z'){ 
return 1; 
} 
return 0; 
} 
//交换两个字母 
void swap(char *a, char *b){ 
char temp = *a; 
*a = *b; 
*b = temp; 
} 
char * Reorder(char *arr, int len){ 
if(arr == NULL || len <= 0){ 
return NULL; 
} 
int *p1 = arr; 
int *p2 = arr; 
While(p1<arr+len && p2<arr+len){ 
While( isUpperAlpha(*p1) ){ 
P1++; 
} 
While( !isUpperAlpha(*p2) ){ 
P2++; 
} 
swap(p1, p2) 
} 
//结束 
return arr; 
} 
int main(){ 
char arr[] = "aaaaaaaaaaaaaaaaaaaaaaaAbcAdeBbDc"; 
printf("%s\n", Reorder(arr, strlen(arr))); 
return 0; 
} 
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文:http://blog.csdn.net/u013630349/article/details/47211257