排序算法比较

#include <iostream>
#include
<vector>
#include
<time.h>
using namespace std;

void printVector(vector<int> v)
{
for(int i = 0; i < v.size(); i++)
cout
<< v[i] << " ";
cout
<< endl;
}

void swapElements(vector<int> &v, int i, int j)
{
int tmp;
if(i >= 0 && i < v.size() && j >= 0 && j < v.size())
{
tmp
= v[j];
v[j]
= v[i];
v[i]
= tmp;
}
}

//选择排序
/*
在要排序的一组数中,选出最小的一个数与第一个位置的数交换;
然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环
到倒数第二个数和最后一个数比较为止。
选择排序是不稳定的。算法复杂度O(n2)
*/

void selectSort(vector<int> &v)
{
for(int i = 0; i < v.size()-1; i++)
{
for(int j = i+1; j < v.size();j++)
{
if(v[j] < v[i])
swapElements(v,i,j);
}
}
}

//直接插入排序
//算法思想简单描述:
//在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排
//好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数
//也是排好顺序的。如此反复循环,直到全部排好顺序。
//直接插入排序是稳定的。算法时间复杂度O(n2)

void insertSort(vector<int> &v)
{
for(int i = 1; i < v.size(); i++)
{
int j = i-1;
int tmp = v[i];
while(j >= 0 && v[j] > tmp)
{
v[j
+1] = v[j];
j
--;
}
v[j
+1] = tmp;
}
}

//冒泡排序
//在要排序的一组数中,对当前还未排好序的范围内的全部数,自上
//而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较
//小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要
//求相反时,就将它们互换。
//冒泡排序是稳定的。算法时间复杂度O(n2)

void bubbleSort(vector<int> &v)
{
int sz = v.size()-1;
while(sz > 1)
{
for(int i = 0; i < sz; i++)
{
int j = i+1;
if(v[i] > v[j])
swapElements(v,i,j);
}
sz
--;
}
}

//希尔排序
//算法思想简单描述:
//
//在直接插入排序算法中,每次插入一个数,使有序序列只增加1个节点,
//并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为
//增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除
//多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现
//了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中
//记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量
//对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成
//一组,排序完成。
//
//下面的函数是一个希尔排序算法的一个实现,初次取序列的一半为增量,
//以后每次减半,直到增量为1。
//
//希尔排序是不稳定的。

void insertSortIncr(vector<int> &v, int incr)
{
for(int i = incr; i < v.size(); i+= incr)
{
int j = i - incr;
int tmp = v[i];
while(j >= 0 && v[j] > tmp)
{
v[j
+incr] = v[j];
j
-= incr;
}
v[j
+incr] = tmp;
}
}

void shellSort(vector<int> &v)
{
int h = v.size()/2;
while(h)
{
insertSortIncr(v,h);
h
= h/2;
}
}

//快速排序
//快速排序是对冒泡排序的一种本质改进。它的基本思想是通过一趟
//扫描后,使得排序序列的长度能大幅度地减少。在冒泡排序中,一次
//扫描只能确保最大数值的数移到正确位置,而待排序序列的长度只
//减少1。快速排序通过一趟扫描,就能确保某个数(以它为基准点吧)
//的左边各数都比它小,右边各数都比它大。然后又用同样的方法处理
//它左右两边的数,直到基准点的左右只有一个元素为止。
//快速排序是不稳定的。最理想情况算法时间复杂度O(nlog2n),最坏O(n2)

void quickSort(vector<int> &v,int l, int r)
{
if(l < r)
{
int pivot = v[l];
int i = l;
int j = r;
while(i < j)
{
while(i < j && v[j] > pivot)
j
--;
if(i < j)
{
v[i]
= v[j];
i
++;
}
while(i < j && v[i] < pivot)
i
++;
if(i < j)
{
v[j]
= v[i];
j
--;
}
v[i]
= pivot;
quickSort(v,l,i
-1);
quickSort(v,i
+1,r);
}
}
}

//堆排序
//堆排序是一种树形选择排序,是对直接选择排序的有效改进。
//堆的定义如下:具有n个元素的序列(h1,h2,...,hn),当且仅当
//满足(hi>=h2i,hi>=2i+1)或(hi <=h2i,hi <=2i+1)(i=1,2,...,n/2)
//时称之为堆。在这里只讨论满足前者条件的堆。
//
//由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项。完全二叉树可以
//很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。
//初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储顺序,
//使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点
//交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点
//的堆,并对它们作交换,最后得到有n个节点的有序序列。
//
//从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素
//交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数
//实现排序的函数。
//
//堆排序是不稳定的。算法时间复杂度O(nlog2n)。

void maxHeapify(vector<int> &v, int i)
{
int l = 2*i;
int r = 2*i+1;
printVector(v);
int pos;
if(l < v.size() && v[l] < v[i])
{
pos
= l;
}
else
pos
= i;
if(r < v.size() && v[r] < v[pos])
pos
= r;

if(pos != i)
{
swapElements(v,i,pos);
maxHeapify(v,pos);
}
}

void heapSort(vector<int> &v)
{
int h = v.size()/2-1;
while(h>=0)
{
maxHeapify(v,h);
h
--;
}
}

int main()
{
vector
<int> v;
for(int i = 0; i < 10; i++)
v.push_back(rand()
%10);
cout
<< "Before Sorting:*****************************************" << endl;
printVector(v);

//selectSort(v);
//insertSort(v);
//bubbleSort(v);
//shellSort(v);
quickSort(v,0,v.size()-1);
//srand(time(NULL));
//heapSort(v);

cout
<< "After Sorting:*****************************************" << endl;
printVector(v);

return 0;
}

算法

时间复杂度

空间复杂度

稳定性

归并

O(nlog2n)

O(n)

稳定

O(nlgn)

O(1)

不稳定

选择

O(n2)

O(1)

不稳定

快排

O(nlgn)

O(lgn)

不稳定

冒泡

O(n2)

O(1)

稳定

希尔

O(1)

不稳定

插入

O(n2)

O(1)

稳定

posted @ 2011-05-13 22:59  摇风清影  阅读(602)  评论(0编辑  收藏  举报