常见排序算法总结

来源:互联网 发布:廊坊sm社交网络 编辑:程序博客网 时间:2024/04/29 08:44

参考了大牛的代码,自己理解整理。vs2008运行正确,如发现有误,请各位大牛指正!

// Sort.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>using namespace std;const int len = 100;class CSort{public:CSort();    ~CSort();void swap(int &a,int &b);    virtual void sort()=0;   //虚函数friend ostream& operator<<(ostream& out,const CSort& csort); //流操作符重载,定义为友元,方便类之间的数据共享protected:int *arr;int length;};//注意此处应该有分号CSort::CSort():length(len)  //构造函数,初始化数组{   arr = new int[length];   for (int i=0; i<length;i++)   {       arr[i] = rand()%1000;//产生随机数   }}CSort::~CSort()   //析构函数,释放申请的内存空间{   delete[] arr;   arr = NULL;   }void CSort::swap(int &a,int &b){  int temp = a;  a = b;  b = temp;}ostream& operator<<(ostream& cout,const CSort& csort){   for (int i=0; i<csort.length;i++)   {   cout<<csort.arr[i]<<" ";   }   cout<<endl;   return cout; //注意}//插入排序  从小到大class CInsertSort : public CSort{public:   void sort();};/************************************************************************//* 直接插入排序:   初始状态认为第一个元素是一个有序的序列,从第二个元素开始逐个插入到有序序列中   的正确位置。当有序序列的最后一个元素比当前元素(用key记录)大,则需要插入,这时   需要移动有序序列中的部分元素,腾出当前元素应该插入的正确位置;否则不插,当前   元素不动。   时间复杂度:O(n*n)  最好情况:O(n)*//************************************************************************/void CInsertSort::sort(){   int i,j;   int key = 0;//当前待插入的数   for (i=1; i<length; i++)   {   if (arr[i-1] > arr[i])//当有序序列的最后一个比当前大,则需要插入,否则不插   {   key = arr[i];   for (j = i-1;j>=0 && arr[j]>key;j--)//寻找待插入数的正确位置   {   arr[j+1] = arr[j];//后移   }   arr[j+1] = key;   }   }}//折半插入排序class CBInsertSort : public CSort{public:void sort();};/*折半插入排序:与直接插入排序所不同的是,在有序序列中找到当前元素的正确位置时采用折半查找的方式,而不是挨个儿比较。时间复杂度:O(n*logn)*/void CBInsertSort::sort(){  int i,j;  for (i=1; i<length; i++)  {      int low = 0;  int high = i-1;  int key = arr[i];  //通过折半找到插入的位置  while(high >= low)//取等号的时候仍要执行  {    int mid = (low + high)/2;if (arr[i] > arr[mid]){low = mid + 1;}else{    high = mid -1;}  }      //找到插入位置high+1后,移位  /*for (j=i-1;j>=high+1;j--)  {  arr[j+1] = arr[j];  }  arr[high+1] = key;*/  //找到插入位置low后,移位  for (j=i-1;j>=low;j--)  {          arr[j+1] = arr[j];  }  arr[low] = key;  }}//希尔排序class CShellInsertSort : public CSort{public:   void sort();private:void shellinsert(int inc);};/**希尔排序:又称缩小增量的插入排序。增量一定的时候,将直接插入排序中的1改为增量inc即可。相比直接插入排序好处在哪?时间复杂度:O(n^1.3)*/void CShellInsertSort::sort(){int a[3]={5,3,1};//增量for (int i=0; i<3; i++){shellinsert(a[i]);}}void CShellInsertSort::shellinsert(int inc)//希尔排序,将直接插入排序中的1改为增量inc即可{int i,j;int key = 0;//当前待插入的数for (i=inc; i<length; i++){if (arr[i-inc] > arr[i])//当有序序列的最后一个比当前大,则需要插入,否则不插{key = arr[i];for (j = i-inc;j>=0 && arr[j]>key;j-=inc)//寻找待插入数的正确位置{arr[j+inc] = arr[j];//后移}arr[j+inc] = key;}}}//冒泡排序class CBubbleSort : public CSort{public:  void sort();};/**冒泡排序:比较长度减1趟,每趟都是从第一个元素开始依次比较,如果前者比后者大,则交换位置每趟找到一个正确的位置,最大值、次大值。。。时间复杂度:O(n^2)  最好情况为:O(n)*/void CBubbleSort::sort(){//bool change = true;//这样设置的目的是什么?可以减少比较次数吗?   for (int i=1; i<=length-1; i++)   {   //change = false;//设置排好   for (int j=0; j<length-i; j++)   {   if (arr[j] > arr[j+1])   {   //change = true;//需要调换位置       swap(arr[j],arr[j+1]);   }   }   }}//快速排序class CFastSort : public CSort{public:   void sort();private:int partition(int low, int high);//进行一次划分,找到一个确定的位置void fastsort(int low, int high);//枢轴元素左右两部分分别进行快速排序};/**快速排序:初始状态将第一个元素作为枢轴元素,进行一次划分,找到它的确定位置左半部分的元素都比枢轴元素小,右半部分的元素都比枢轴元素大然后分别递归的对左右两部分的元素进行快速排序。*/void CFastSort::sort(){    fastsort(0,length-1);}/**找到枢轴元素的位置,对数组进行划分。设置两个游标:low,high.如果游标high对应的元素大于或等于枢轴元素,则游标high减1;否则将该值赋洞口如果游标low对应的元素小于或等于枢轴元素,则游标low加1;否则将该值赋给洞口当low=high时循环结束,它们所指示的位置就是枢轴元素所在的位置。时间复杂度:O(n*logn)  最坏情况:O(n^2)*/int CFastSort::partition(int low, int high){   int key = arr[low];//枢轴元素初始化为第一个元素   为了方便理解,可以成为挖洞   while (low < high)   {   while (low < high && arr[high] >= key)   {   high--;   }   arr[low] = arr[high];//找到第一个比key小的元素   while (low < high && arr[low] <= key)   {   low++;   }   arr[high] = arr[low];//找到第一个比key大的元素          }   arr[low] = key;   return low;}void CFastSort::fastsort(int low, int high){if (low < high){int keypos = partition(low,high);fastsort(low,keypos-1);fastsort(keypos+1,high);}   }//堆排序 从小到大 初始堆为大根堆class CHeapSort : public CSort{public:void sort();private:void heapsort();  //堆排序void adjustheap(int s,int w); //对堆进行调整 s表示待调整的位置下标,w表示待排序的元素个数};void CHeapSort::sort() //实现父类的虚函数{   heapsort();}/**堆排序:初始状态按照完全二叉树的结构依次排列形成一个初始堆。然后从第一个非终端节点开始到根结点依次调整以该结点为根的子树,形成一个大根堆。之后将堆顶元素和最后一个元素交换,输出堆顶元素。接着调整新形成的堆,注意这时是直接从根结点开始调整堆的。然后将堆顶元素和最后一个元素交换。。。其中有个很重要的调整堆的操作。整个排序的过程,实际上是在数组中进行的。时间复杂度:O(n*logn)*/void CHeapSort::heapsort(){   //首先从第一个非终端节点开始调整,初始化为大根堆for (int i=length/2-1; i>=0; i--){adjustheap(i,length);}for (int j=length-1; j>0; j--){swap(arr[0],arr[j]); //将堆顶元素将最后一个元素交换adjustheap(0,j);  //交换后,重新调整堆为大根堆}}/**调整堆的过程:有两个参数:s表示待调整的位置下标,w表示待排序的元素个数局部变量i表示的是最大值的下标用key记录待调整的元素,比较时是从它的左孩子开始的,注意要判断待调整的元素是否有两个孩子。如果它比孩子大,则不需要调整否则将较大的孩子的值赋给待调整的元素。s变为该孩子的下标,继续比较。最后找到待调整元素的正确位置。调整结束*/void CHeapSort::adjustheap(int s,int w){   int key = arr[s];//key记录待调整的元素   for (int i=2*s+1; i<w; i=2*i+1)   {   if (i<w-1 && arr[i]<arr[i+1])  //下标i表示的是最大值的下标,i<m-1:保证其有左右孩子时,才进行左右孩子的比较   {         i++;      }  if (key>arr[i]) //比孩子都大,不需要调整  {  break;  }  arr[s]=arr[i];  s=i;   }   arr[s]=key;}//选择排序class CSelectionSort : public CSort{public:void sort();};/*选择排序:比较长度减1次,每次找到一个最小值,和未排序序列中的第一个元素(即i所记录的)进行交换用一个下标记录最小值的下标时间复杂度:O(n^2)*/void CSelectionSort::sort(){  for (int i=0; i<length-1; i++)  {  int minpos = i;//minpos表示最小值的下标  for (int j = i+1; j<length; j++)  {  if (arr[j] < arr[minpos])  {  minpos = j;//遍历一趟找到最小值的下表  }  }  if (minpos!=i)  {swap(arr[i],arr[minpos]);//注意此处是交换  }  }}//归并排序class CMergingSort : public CSort{public:void sort();private:void mergesort(int left,int right);void merge(int left,int mid,int right);};void CMergingSort::sort(){  mergesort(0,length-1);}/*归并排序:采用递归的思想,从中间将数组划分为两部分,然后分别递归的对两部分进行归并排序然后将两部分排好序的合并到一起,完成排序。时间复杂度:O(n*logn)*/void CMergingSort::mergesort(int left,int right){   if (left<right)   {      int mid = (left+right)/2;  mergesort(left,mid); //左半部分排好序  mergesort(mid+1,right); //右半部分排好序  merge(left,mid,right); //左右两部分排序   }}/*归并两个排好序的部分的过程:申请一个临时数组,挨个儿比较两个部分里的元素,先将小的元素加入到临时数组中最后将临时数组中的元素复制到原数组中即可*/void CMergingSort::merge(int left,int mid,int right){   int i=left;   int j=mid+1;   int *tem = new int[right-left+1];//申请和数组大小相等的内存空间 临时空间   int k=0;   while (i<=mid && j<=right)   {   if (arr[i] < arr[j])   {   tem[k++]=arr[i++];   }   else   {   tem[k++]=arr[j++];   }   }   while (i<=mid)   {   tem[k++]=arr[i++];   }   while (j<=right)   {   tem[k++]=arr[j++];   }   for (i=0,j=left;j<=right;i++,j++)   {      arr[j]=tem[i];   }   delete[] tem;}int _tmain(int argc, _TCHAR* argv[]){CSort *pcsort;//pcsort = new CInsertSort();  //插入排序    //pcsort = new CBInsertSort();  //折半插入排序//pcsort = new CShellInsertSort(); //希尔排序//pcsort = new CBubbleSort();  //冒泡排序//pcsort = new CFastSort();//快速排序//pcsort = new CSelectionSort();//选择排序//pcsort = new CHeapSort();//堆排序pcsort = new CMergingSort();//归并排序cout<<"排序前:"<<endl;cout<<*pcsort;pcsort->sort();cout<<"排序后:"<<endl;    cout<<*pcsort;system("pause");return 0;}



 


 

原创粉丝点击