常见的排序算法

来源:互联网 发布:淘宝脸部验证 编辑:程序博客网 时间:2024/05/29 03:59

排序算法是面试笔试中必定要涉及的内容,常见的排序算法有:插入排序,冒泡排序,选择排序,快速排序,堆排序,希尔排序,归并排序,基数排序等,下面是我自己针对这几种算法进行一些总结和实现。

(1)按照时间性能来分,可以划分为三类排序算法:
1. O(nlogn): 快速排序,堆排序,归并排序,其中以快排为最佳;
2. O(n2): 直接插入排序,冒泡排序,简单选择排序,其中以直接插入排序为最佳,尤其对于那些关键字近似有序的记录序列;
3. O(n): 只有基数排序,基数排序适合n值很大而关键字较小的序列。
(2)性能易变性:
当待排序列有序时,直接插入排序和冒泡排序能到达O(n),而对于快速排序而言,这反而是最不好的情况,此时时间性能蜕化为O(n2);简单选择排序,堆排序和归并排序的时间复杂度不随数列中关键字的分布

而改变。
(3)稳定性:
选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,
冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。

各排序时间复杂度和空间复杂度对比表:

常见的排序算法

平台:VS 2008
算法实现:
---------------插入排序(直接插入)--------------

#include "stdafx.h"
#include "stdio.h"

#define LEN 10

void sort_insert(int a[],int len)
{
 int i,j,key;
 for (i = 1; i < len; i++)
 {
  key = a[i];
  //把i之前大于a[i]的数据向后移动
  for (j = i - 1; ((a[j] > key) && j >= 0);j--)
  {
   a[j + 1] = a[j];
  }
  a[j + 1] = key;  //最后把最小的key赋值给首元素a[0]
 }
}
int _tmain(int argc, _TCHAR* argv[])
{
 int a[LEN] = {3,6,2,1,0,10,9,12,5,10};
 int k;
 sort_insert(a,LEN);
 for (k = 0; k < LEN; k++)
 {
  printf("M",a[k]);
 }
 return 0;
}


---------------冒泡排序--------------

#include "stdafx.h"
#include "stdio.h"

#define LEN 10

void bubble_sort(int arry[],int len)
{
 int i,j,tmp;
 for (i = 0; i < len - 1; i++)
 {
  for (j = i + 1; j < len; j++)
  {
   if (arry[i] > arry[j])
   {
    tmp = arry[i];
    arry[i] = arry[j];
    arry[j] = tmp;
   }
  }
 }
}

int _tmain(int argc, _TCHAR* argv[])
{
 int a[LEN] = {3,6,2,1,0,10,9,12,5,10};
 int k;
 bubble_sort(a,LEN);
 for (k = 0; k < LEN; k++)
 {
  printf("M",a[k]);
 }
 return 0;
}


---------------选择排序(简单选择排序)--------------


#include "stdafx.h"
#include "stdio.h"

#define LEN 10

//交换数组中的两个数
void swap(int v[],int i,int j)
{
 int tmp;
 tmp = v[i];
 v[i] = v[j];
 v[j] = tmp;
}
//选择排序算法
void selection_sort(int arry[],int len)
{
 int i,j,flag;
 for (j = 0; j < len; j++)
 {
  flag = j;
  for (i = j; i < len; i++)
  {
   if (arry[i] < arry[flag])
   {
    flag = i;
   }
  }
  swap(arry,j,flag);
 }
}

int _tmain(int argc, _TCHAR* argv[])
{
 int a[LEN] = {3,6,2,1,0,10,9,12,5,10};
 int k;
 selection_sort(a,LEN);
 for (k = 0; k < LEN; k++)
 {
  printf("M",a[k]);
 }
 return 0;
}

---------------快速排序--------------

#include "stdafx.h"
#include "stdio.h"

#define LEN 10

//交换数组中的两个数
void swap(int v[],int i,int j)
{
 int tmp;
 tmp = v[i];
 v[i] = v[j];
 v[j] = tmp;
}
//快速排序算法
void quick_sort(int v[],int left,int right)
{
 int i,last;
        //最后一次递归结束出口
 if (left >= right)
 {
  return;
 }
 //确定大概中间位置元素为分区元素
 //把分区元素移动到最左边
 swap(v,left,(left + right)/2);
 last = left;

 //分区:把小于分区元素的数全部移动到它的左边
 //把大于分区元素的数全部移动到它的右边
 //结果为:{小于X} X {大于X}
 for (i = left + 1; i <= right; i++)
 {
  if (v[i] < v[left])
  {
   ++last;
   swap(v,last,i);
  }
 }
 //恢复分区元素
 swap(v,left,last);
 //一次快排结束

 //递归调用排序算法
 quick_sort(v,left,last -1);
 quick_sort(v,last + 1,right);
}

int _tmain(int argc, _TCHAR* argv[])
{
 int a[LEN] = {3,6,2,1,0,10,9,12,5,10};
 int k;
 quick_sort(a,0,LEN - 1);
 for (k = 0; k < LEN; k++)
 {
  printf("M",a[k]);
 }
 return 0;
}
算法具体执行过程:
举例:a[6] = {3,6,2,5,0,4,7};
选定中间元素(0+6)/2 = 3,即a[3]为5:
3 6 2 5 0 4 7
把5与left互换;
5 6 2 3 0 4 7
left和last都指向5;
i从left + 1开始,即从6开始;
如果小于a[left]内的数,则和++last互换,否则不执行操作;
执行过程如下:
5 6 2 3 0 4 7
5 2 6 3 0 4 7
5 2 3 6 0 4 7
5 2 3 0 6 4 7
5 2 3 0 4 6 7
5 2 3 0 4 6 7
最后交换left和last,此时last指向的是4
4 2 3 0 5 6 7
最终一次快排结果为:{4,2,3,0} 5 {6,7}
然后在{4,2,3,0}和{6,7}两个集合中递归快排


---------------堆排序--------------

#include "stdafx.h"
#include "stdio.h"

#define LEN 10

//调整筛选
void shift(int h[],int n,int m)
{
 //h为数组,n为元素个数,m为从第m个元素开始调整
 int j,tmp;
 tmp = h[m];//保存每次需要调整的元素
 j = 2 * (m + 1) - 1;
 
 while (j <= n)
 {
  if ((j < n)&&(h[j] < h[j + 1]))
  {
   j += 1;
  }
  if (tmp < h[j])
  {
   h[m] = h[j];
   m = j;//标记m
   j = 2 * (m + 1) - 1;
  }
  else
  {
   j = n + 1;//跳出循环
  }
 }
 h[m] = tmp;//把tmp保存的元素插入到正确位置
}

//堆排序
void HeapSort(int p[],int n)
{
 int i,k,t;
 k = n/2;

 for (i = k -1; i >= 0; i--)
 {
  shift(p,n-1,i);
  //i = k -1,n - 1都是与数组从0开始有关
 }
 for (i = n - 1; i >= 1; i--)
 {
  //把最大元素移到倒数第i个位置
  //把倒数第i个元素移到堆顶
  t = p[0];
  p[0] = p[i];
  p[i] = t;
  shift(p,i-1,0);
 }

}

int _tmain(int argc, _TCHAR* argv[])
{
 int a[LEN] = {3,6,2,1,0,10,9,12,5,10};
 int k;
 HeapSort(a,LEN);
 for (k = 0; k < LEN; k++)
 {
  printf("M",a[k]);
 }
 return 0;
}

---------------希尔排序--------------

/#include "stdafx.h"
#include "stdio.h"

#define LEN 10

void shellSort(int a[],int n)
{
 int i,j,tmp,step;

 for( step = n/2; step > 0; step = step/2 )
 {
  for(i = step;i < n;i++)
  {
   tmp = a[i]; 

   j = i - step;

   while((j >= 0) && (a[j]>tmp))
   {
    a[j + step] = a[j];
    a[j] = tmp;

    j = j - step;
   }
  }
 }
}

 

int _tmain(int argc, _TCHAR* argv[])
{
 int a[LEN] = {3,6,2,1,0,10,9,12,5,10};
 int k;
 shellSort(a,LEN);
 for (k = 0; k < LEN; k++)
 {
  printf("M",a[k]);
 }
 return 0;
}
----------------------相关链接--------------------------

链表与时间复杂度O:
a.归并两个链表(有序)时,采用快速排序,时间复杂度为O(nlogn);
b.单链表,双链表插入和删除元素的时间复杂度都为O(n);

0 0
原创粉丝点击