面试常考之排序算法

来源:互联网 发布:淘宝点击率是什么意思 编辑:程序博客网 时间:2024/05/29 07:30

总结一下面试常常遇到的基础排序算法(默认升序),方便接下来复习:

1.选择排序

思想:每一趟选出最小值
复杂度分析:最坏情况O(n^2),最好情况O(n^2),平均情况O(n^2),额外空间O(1)
稳定性:不稳定
例子:9 3 6 2 8 7

  • 2 3 6 9 8 7 (第一趟)
  • 2 3 6 9 8 7 (第二趟)
  • 2 3 6 9 8 7 (第三趟)
  • 2 3 6 7 8 9 (第四趟)
  • 2 3 6 7 8 9 (第五趟)
  • 2 3 6 7 8 9 (第六趟)

代码

void selectSort(int *a,int len){    if(len <= 0) return;    for(int i=0;i<len-1;i++)    {        int min = a[i];        //这个循环选出第i趟最小值        for(int j=i+1;j<len;j++)        {            if(min>a[j])            {                min = a[j];            }        }        if(min != a[i])        {            swap(a,min,a[i]);        }    }}

2.插入排序

思想:插入第i个元素时,与前面已经排好序的i-1个元素比较,如果它不是插入到最后一个位置,那么大于它的序列就要顺序向后移动一个位置。
复杂度分析:最坏情况O(n^2),最好情况O(n),平均情况O(n^2),额外空间O(1)
稳定性:稳定
例子:9 3 6 2 8 7

  • 9 3 6 2 8 7(第一趟)
  • 3 9 6 2 8 7(第二趟)
  • 3 6 9 2 8 7(第三趟)
  • 2 3 6 9 8 7(第四趟)
  • 2 3 6 8 9 7(第五趟)
  • 2 3 6 7 8 9(第六趟)

代码

void insertSort(int *a,int len){    if(len <= 0) return;    for(int i=1;i<len;i++)    {        int j = i-1; //要插入的元素        int temp = a[i];        while(j>=0 && temp<a[j])        {            //后移            a[j+1] = a[j];            j--;        }        a[j+1] = temp; //多执行了一次j--,所以要+1    }}

3.希尔排序(递减增量排序)

思想:相距增量(d)的元素为一组,内部采用插入排序方法使组内有序。然后增量减小一个单位,再组内排序,迭代直到增量为1。
复杂度分析:最坏情况O(n^1.3),最好情况O(n),平均情况O(n^2),额外空间O(1)
稳定性:不稳定
例子:9 3 6 2 8 7 (初始:元素个数为6,设置d= 6/2=3,那么9和2为一组,3和8为一组,6和7为一组)

  • 2 3 6 9 8 7(第一趟d=3,9和2交换位置,其他两组已经有序)
  • 2 3 6 7 8 9(第二趟d=2,2 6 8一组,3 9 7一组,9和7交换)
  • 2 3 6 7 8 9(第三趟d=1,只剩一组,已经有序)

代码

void shellSort(int *a,int len){    if(len <= 0) return;    for(int d=len/2;d>=1;d--)    {        for(int i=d;i<len;i++)        {            //每一组内部采取插入排序            if(a[i-d]>a[i])            {                int temp = a[i];                int k = i-d;                while(k>=0 && a[k]>= temp)                {                    a[k+d] = a[k];                    k = k-d;                }                a[k+d] = temp;            }        }    }}

4.冒泡排序

思想:每一趟相邻元素两两比较,逆序则交换(想象成泡泡往上冒),每一次保证最大的到达顶部,排好序的最大元素不纳入下一趟排序。
复杂度分析:最坏情况O(n^2),最好情况O(n),平均情况O(n^2),额外空间O(1)
稳定性:稳定
例子:9 3 6 2 8 7

  • 3 6 2 8 7 9(第一趟)
  • 3 2 6 7 8 9 (第二趟)
  • 2 3 6 7 8 9 (第三趟)
  • 2 3 6 7 8 9 (第四趟)
  • 2 3 6 7 8 9 (第五趟)
  • 2 3 6 7 8 9 (第六趟)

代码

void bubbleSort(int *a,int len){    if(len <= 0) return;    for(int i=len-1;i>0;i--)    {        for(int j=0;j<=i;j++)        {            if(a[j]>a[j+1])            {                swap(a,a[j],a[j+1]);            }        }    }}

5.快速排序

思想:确定pivot之后(一般取第一位元素作为pivot),扫描一趟,比pivot小的放左边,比pivot大的放右边。再对左子序列和右子序列分别调用函数本身(递归),直到不能再分出左子序列和右子序列。
复杂度分析:最坏情况O(n^2),最好情况O(nlogn),平均情况O(nlogn),额外空间O(nlogn)
稳定性:不稳定
例子:4 8 2 6 5 3

  • 2 3 4 8 6 5(第一趟)
  • 2 3 4 6 5 8(第二趟)
  • 2 3 4 5 6 8(第三趟)

代码

void quickSort(int *a,int left,int right){    if(right <= left) return;    int pivot = a[left];    int i = left;    int j = right;    while(i < j)    {        while(j>i && a[j]>= pivot) //从右到左找比pivot小的        {            j--;        }        if(j>i)        {            a[i] = a[j];            i++;        }        while(j>i && a[i]<= pivot) //从左到右找比pivot小的        {            i++;        }        if(j>i)        {            a[j] = a[i];            j--;        }    }    a[i] = pivot; //完成一趟    quickSort(a,l,i-1); //左子序列    quickSort(a,i+1,r); //右子序列}

6.归并排序

思想
复杂度分析:最坏情况O(nlog),最好情况O(nlogn),平均情况O(nlogn),额外空间O(n)
稳定性:稳定
例子:4 8 2 6 5 3

  • 4 8 2  | 6 5 3
  • 4 |  8 2  | 6  |  5 3

代码

void mergeSort(int *a,int first,int last, int *temp){    if(first < last)    {        int mid = (first + last)/2;        mergeSort(a,first,mid,temp); //对左子序列排序        mergeSort(a,mid+1,last,temp); //对右子序列排序        mergeArray(a,first,mid,last,temp); //合并    }}//两个有序子序列合并成一个新的序列void mergeArray(int *a,int left,int mid,int right,int *temp){    int i = left, j = right;    int k = 0;    //循环挑出相对较小的放入临时数组temp中从而保证有序    while(i<=mid && j<=right)    {        if(a[i] < a[j])        {            temp[k++] = a[i++];        }else        {            temp[k++] = a[j++];        }    }    while(i <= mid) //如果左子序列还有剩,按序填入    {        a[k++] = a[i++];    }    while(j <= right) //如果右子序列还有剩,按序填入    {        a[k++] = a[j++];    }    //把temp中放回原数组    for(int m=0; m<k;m++)    {        a[first+m] = temp[m];    }}

7.堆排序

思想
复杂度分析:最坏情况O(nlogn),最好情况O(nlogn),平均情况O(nlogn),额外空间O(1)
稳定性:不稳定
性质
1.节点的性质:i表示当前节点,则父节点为(i-1)/2,左孩子节点为(2*i+1),右孩子节点为(2 *i+2);
2.最大堆的父节点要大于等于子节点,(最小堆相反);
3.在新建堆的过程中,采用AdjustDown堆化数组,从n/2节点开始,因为大于n/2的是叶子节点。

代码

//以最大堆为例//堆调整void AdjustDown(int a[],int k,int len)//将元素a[k]向下调整{    a[0] = a[k];     //a[0]暂存,相当于temp    for(int i=2*k; i<=len; i*=2)    {        if(i<len && a[i]<a[i+1])        {            i++;      //取值较大的i的下标        }        if(a[0]>=a[i])        {            break;     //a[0]>子节点中最大的值,结束筛选        }else        {            a[k] = a[i]; //否则交换            k = i;       //跟踪k的下标        }    }    a[k] = a[0];         //调整结束后,把a[k]的值补上}//新建堆void BuildMaxHeap(int a[],int len){    for(int i=len/2;i>0;i--)    //从i=len/2 - 1,反复调整堆    {        AdjustDown(a,i,len);    //从上往下调整直到子树满足最大堆    }}//堆排序--调用前两个函数void HeapSort(int a[],int len){    BuildMaxHeap(a,len);   //初始建堆    for(int i=len;i>1;i--)    {        swap(a[i],a[1]);   //可得到堆顶元素        AdjustDown(a,1,i-1);   //整理剩余的i-1个元素    }}

写到后面有点晕掉了,…(◎ロ◎)… ,休息一下…

0 0
原创粉丝点击