面试/笔试数据结构之排序算法篇

来源:互联网 发布:嵌入式linux终端 编辑:程序博客网 时间:2024/05/20 05:22

面试/笔试数据结构之排序算法篇

面试时数据结构应该是面试官们一定会问到的知识块,最常见的就是对于排序、查找等算法的考察。这里先列出一些常见易考,并且比较重要的排序算法。这里都以排成增序为例,如有错误、不好之处敬请指出。

1、 直接插入排序 
假设我们有一个序列{a0,a1,a2,a3……an},将a0看成是一个有序序列,a1~an看成是无序序列,插入排序就是将a1和a0比较,如果比a0小则将其插到a0前面,如果比a0大,则不做事情,这样一次之后前两个位置就是有序的,第三个到第n个仍是无序的。然后,再a2和前两个做比较,将其插入到合适的位置,这样之后,前三个元素都是有序的,第四个到第n个是无序的。如此往复,直到序列有序即可。

void InsertSort(int a[],int len){    int j,temp;    for (int i=1; i<len; i++)    {        if (a[i]<a[i-1]) {            temp=a[i];            for (j=i-1; a[j]>temp&&j>=0; j--) {                a[j+1]=a[j];            }            a[j+1]=temp;        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

2、 希尔排序 
假设我们有一个序列{a0,a1,a2,a3……an},希尔排序的基本思想是会将序列分割成若干个子序列,然后再对各个子序列进行插入排序。因此希尔排序会有一个增量d,其初始值一般为序列长度的一半,即d=n/2,这样将一个序列分为两个子序列,再分别对两个子序列做插入排序。之后d取值为n/4,再对子序列做插入排序,如此往复,直到d=1,此时序列基本有序,再对其进行一次插入排序即可。

void ShellSort(int a[],int len){    int d;    for (d=len/2; d>0; d/=2) {//步长        for (int i=0; i<d; i++) {//直接插入排序            for (int j=i+d; j<len; j+=d) {                if (a[j]<a[j-d]) {                    int temp=a[j];                    int k=j-d;                    while (k>=0&&a[k]>temp) {                        a[k+d]=a[k];                        k-=d;                    }                    a[k+d]=temp;                }            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

上面的代码是最能体现希尔排序思想的,下面给出两种稍加改进的代码。

void shellsort1(int a[], int n){    int j, d;    for (d = n / 2; d > 0; d /= 2)        for (j = d; j < n; j++)//从数组第d个元素开始            if (a[j] < a[j - d])//每个元素与自己组内的数据进行直接插入排序            {                int temp = a[j];                int k = j - d;                while (k >= 0 && a[k] > temp)                {                    a[k + d] = a[k];                    k -= d;                }                a[k + d] = temp;            }}void shellsort2(int a[], int n){    int i, j, d;    for (d = n / 2; d > 0; d /= 2)        for (i = d; i < n; i++)            for (j = i - d; j >= 0 && a[j] > a[j + d]; j -= d)                swap(&a[j], &a[j + d]);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

3、 冒泡排序 
两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

void swap(int *a,int *b){    int temp;    temp=*a;    *a=*b;    *b=temp;}void BubbleSort(int a[],int len){    int i,j;    for (i=0;i<len;i++)    {        for (j=i+1;j<len;j++)        {            if (a[i]>a[j])                swap(&a[i],&a[j]);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

下面也给出冒泡排序的另外两种实现。

void BubbleSort1(int a[],int len){    for (int i=0;i<len;i++)    {        for(int j=len-2;j>=i;j--)        {            if (a[j]>a[j+1]) //前者与后者比较,这里与前面算法的区别                swap(&a[j],&a[j+1]);        }    }}void BubbleSort2(int a[],int len){    int flag=1;    for (int i=0;i<len &&flag;i++)    {        flag=0;        for (int j=len-2;j>=i;j--)        {            if (a[j]>a[j+1])            {                swap(&a[j],&a[j+1]);                flag=1;            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

4、 快速排序 
假设我们有一个序列{a0,a1,a2,a3……an},在快速排序算法里,我们将第一个元素用作枢轴纪录关键字key,并有一个low指针指向第一个元素,有一个high指针指向最后一个元素,当low < high时,将a[high]和key做比较,如果a[high]>=key,则high–,否则交换low和high位置的元素;当low < high时,将a[low]和key做比较,如果a[low]<=key,则low++,否则交换low和high位置的元素。直到low>=high,一次排序结束,此时key左边的值都比它小,key右边的值都比它大。

int Partiton(int a[],int low,int high){    int key;    key=a[low];//枢轴的选取可以选取中间值    while (low<high)    {        while (low<high &&a[high]>=key)            high--;        swap(&a[high],&a[low]);        while (low<high && a[low]<=key)            low++;        swap(&a[high],&a[low]);    }    return low;}void Qsort(int a[],int low,int high){    int pivot;    if (low<high)    {        pivot=Partiton1(a,low,high);        Qsort(a,low,pivot-1);        Qsort(a,pivot+1,high);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

下面的代码是对快排的一种优化。

int Partiton1(int a[],int low,int high)/*y优化不需要的交换*/{    int temp,key;    key=a[low];    temp=key;    while (low<high)    {        while (low<high &&a[high]>=key)            high--;        a[low]=a[high];        while (low<high && a[low]<=key)            low++;        a[high]=a[low];    }    a[low]=temp;    return low;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

5、 简单选择排序 
假设我们有一个序列{a0,a1,a2,a3……an},简单选择排序就是将这n个元素遍历一遍选出最小的,再和第一个交换;再从剩下2~n个元素中选出最小的和第二个交换,重复以上步骤即可。

void SelectSort(int a[],int len){    int min;    for (int i=0;i<len;i++)    {        min=i;        for (int j=i+1;j<len;j++)        {            if (a[min]>a[j])                min=j;        }        if (i!=min)            swap(&a[min],&a[i]);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

6、 堆排序 
输出堆顶的最小值之后,使剩下n-1个元素的序列重又建成一个堆,则得到n个元素中的次小值。如此反复执行,便能得到一个有序序列。

void HeapAdjust(int a[],int s,int m){    int temp,j=0;    temp=a[s];    for (j=2*s+1;j<m;j=j*2+1)    {        if (j<m && a[j]<a[j+1])            ++j;        if (j<m && temp>=a[j])            break;        a[s]=a[j];        s=j;    }    a[s]=temp;}void HeapSort(int a[],int len){    int i;    for (i=(len)/2-1;i>=0;i--)        HeapAdjust(a,i,len);    for (i=len-1;i>=1;i--)    {        swap(&a[0],&a[i]);        HeapAdjust(a,0,i-1);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

下面给出上述各种算法的时间复杂度、空间复杂度、稳定性等。 
这里写图片描述

0 0
原创粉丝点击