/***********************************************************************************************************************
文件说明:
为面试准备的【内部排序算法】
开发环境:
Win10+VS2012
时间地点:
陕西师范大学 文津楼
作 者:
九 月
***********************************************************************************************************************/
#include<iostream>
using namespace std;
#define ARRAY_LENTGTH 15
typedef int ElemType;
ElemType srcData[ARRAY_LENTGTH] = {10,9,8,7,6,5,4,3,2,1,1000,2000,900,300,200};
//===============================================================================================================================
//=====================================================【插入排序算法】==========================================================
//===============================================================================================================================
/***********************************************************************************************************************
函数原型:
template<typename DataType>void InsertSort(DataType arrayT[],int iLength)
函数说明:
【排序算法1】---------【直接插入排序】
性能分析:
【1】【空间效率】:仅使用了数个辅助单元,因而空间复杂度为O(1);
【2】【时间效率】:在排序过程中,向有序子表中逐个插入元素的操作进行了n-1趟,每趟的操作部分分为【比较关键字】和
【移动元素】,而【比较次数】和【移动次数】取决于待排序表的【初始状态】。
【3】【最好情况下】:表中的元素已经有序,此事每插入一个元素,都只需比较一次而不用移动元素,因而时间复杂度为O(n).
【4】【最坏情况下】:表中的元素刚好和排序结果中的元素顺序相反【逆序】时,总的比较次数达到最大,总的移动次数也达
到最大。
【5】【平均情况下】:考虑待排序表中的元素是随机的,此时,可以去上述最好与最坏情况的平均值作为平均情况下的复杂度,
总的比较次数和移动次数约为(n*n)/4
【6】由此,【直接插入排序算法】的【时间复杂度】为O(n*n).虽然【折半插入算法】的【时间复杂度】也为O(n*n),但是对于
【数据量比较小】的【排序表】,【折半插入排序】往往表现出更好的性能。
【7】【使用性】:
【直接插入排序算法】适用于【顺序存储】和【链式存储】的【线性表】
***********************************************************************************************************************/
template<typename DataType>void InsertSort(DataType srcData[],int iLength)
{
DataType tempT; //【1】定义一个哨兵
int j = 0;
for(int i=0;i<iLength;i++) //【2】n个数,进行n-1趟的插入
{
tempT = srcData[i];
j = i-1;
while (tempT<srcData[j]) //【3】搜索数据应该插入的位置
{
srcData[j+1] = srcData[j];
j = j-1;
}
srcData[j+1] = tempT; //【4】直接插入
}
}
/***********************************************************************************************************************
函数原型:
template<typename DataType>void BinInsertSort(DataType srcData[],int iLength)
函数说明:
【排序算法2】---------【折半插入排序】
性能分析:
【1】【折半插入排序算法】是【直接插入排序算法】的改进算法,两者算法的基本性能一致,但是【折半插入排序算法】相比
【直接插入排序算法】来说,相互比较的次数减少
【2】在【数据量较小】的排序过程中,【折半插入排序算法】往往表现出比【直接插入排序算法更好的性能】
***********************************************************************************************************************/
template<typename DataType>void BinInsertSort(DataType srcData[],int iLength)
{
DataType tempT; //【1】定义一个哨兵
int j = 0;
int iMid = 0;
int iHigh = 0;
int iLow = 0;
for(int i=1;i<iLength;i++)
{
tempT = srcData[i];
iLow = 0;
iHigh = i -1;
while (iLow<=iHigh)
{
iMid = (iLow+iHigh)/2;
if(tempT<srcData[iMid])
{
iHigh = iMid - 1;
}
else
{
iLow = iMid + 1;
}
}//while
for(j=i-1;j>=iLow;j--)
{
srcData[j+1] = srcData[j];
}
srcData[iLow] = tempT;
}
}
/***********************************************************************************************************************
函数原型:
template<typename DataType>void BinInsertSort(DataType srcData[],int iLength)
函数说明:
【排序算法3】---------【希尔排序】
性能分析:
【1】【空间效率】:仅使用了常数个辅助单元,因而空间复杂度为O(1);
【2】【时间效率】:由于【希尔排序】的【时间复杂度】依赖于【增量序列的函数】,这涉及数学上尚未解决的难题,所以时间
复杂度分析比较困难。但是,希尔排序最坏情况下的【时间复杂度】为O(n*n).
【3】【适用性】:【希尔排序算法】仅适用于当【线性表】为【顺序存储】的情况。
***********************************************************************************************************************/
template<typename DataType>void ShellSort(DataType srcData[],int iLength)
{
for(int d=(iLength/2);d>=1;d = d/2) //【1】设置(起始增量;循环条件;增量变化规则)
{
for(int k=0;k<d;k++) //【2】增量为k,就有k个子序列
{
for(int i=k+d;i<iLength;i++) //【3】对每一个子序列进行【直接插入排序】
{
DataType tempT = srcData[i];
int j = i -1;
while (tempT<srcData[j])
{
srcData[j+1] = srcData[j];
j = j-1;
}
srcData[j+1]=tempT;
}//for i
}//for k
}//for d
}
//===============================================================================================================================
//=====================================================【交换排序算法】==========================================================
//===============================================================================================================================
/***********************************************************************************************************************
函数原型:
template<typename DataType>void BubbleSort(DataType srcData[],int iLength)
函数说明:
【排序算法4】---------【冒泡排序】
性能分析:
【1】【空间效率】:仅使用了常数个辅助单元,因而空间复杂度为O(1);
【2】【时间效率】:当初始序列有序时,显然第一趟冒泡后bChangedFlag依然为false(本趟冒泡没有元素交换)。从而直接跳出
循环,比较次数为n-1次,移动次数为0,从而最好情况下的时间复杂度为O(n);当初始序列为逆序时,需要
进行n-1趟排序,第i趟排序需要进行n-i次关键字的比较,而且每次比较都需要进行关键字的交换,从而最
坏情况下,冒泡排序的时间复杂度为O(n*n);其平均的时间复杂度也为O(n*n).
【3】【注意】:【冒泡排序】中所产生的【有序子序列】一定是【全局有序】的(不同于直接插入排序),也就是说有序子序列中
的所有元素的关键字一定小于或者大于【无序子序列】中所有元素的关键字,这样每一趟排序都会将一个元
素放在其最终的位置上。
***********************************************************************************************************************/
template<typename DataType>void BubbleSort(DataType srcData[],int iLength)
{
bool bChangedFlag = true; //【0】表示本趟冒泡排序是否发生了交换
for(int i=0;i<iLength-1;i++) //【1】外循环控制排序的【循环次数】,N个数,需要N-1趟的比较
{
bChangedFlag = false; //【2】表示本趟冒泡是否发生了交换的标志
for(int j=0;j<iLength-1-i;j++)
{
if(srcData[j]>srcData[j+1]) //【3】这样经过一次排序后,最后一个数为确定的、最大的数
{
int iTemp = srcData[j];
srcData[j] = srcData[j+1];
srcData[j+1]= iTemp;
bChangedFlag= true;
}
}
if(bChangedFlag==false) //【4】如果本趟遍历后没有发生交换,说明表已经有序
{
break;
return;
}
}//for i
}
/***********************************************************************************************************************
函数原型:
【1】template<typename DataType>int QuickPartition(DataType srcData[],int iLeft,int iRight)
【2】template<typename DataType>static void QuickSort(DataType srcData[],int iLeft,int iRight)
函数说明:
【排序算法5】---------【快速排序】
性能分析:
【1】【空间效率】:由于【快速排序】是【递归】的,需要借助一个【递归工作栈】来保存每一层【递归调用】的【必要信息】,
其容量应与递归调用的最大深度一致。最好情况下为log2(n+1);最坏情况下,因为要进行n-1次递归调用,
所以栈的深度为0(n),平均情况下为O(log2n)
【2】【时间效率】:【快速排序】的【运行时间】与【划分】是否对称有关,而后者又与具体使用的【划分算法】有关,快速排
序最坏情况发生在两个划分区域分别包含n-1个元素和0个元素时,这种最大深度的不对称,若发生在每一层
递归上,即对应于初始排序表基本有序或者基本逆序时,就得到最坏情况下的时间复杂度为O(n*n).
【3】【时间效率】:好在,【快速排序】的【平均情况】下的【运行时间】与其【最佳情况下】的【运行时间】很接近,而不是
接近【最坏情况下的运行时间】。【快速排序】是【所有内部排序算法】【平均性能最优】的【排序算法】
【4】在【快速排序】中,并产【有序的子序列】,但每一趟排序后,将一个【基准元素】放到其最终的位置上。
***********************************************************************************************************************/
//【1】对【待排序列】进行一次【快速排序】
template<typename DataType>int QuickPartition(DataType srcData[],int iLeft,int iRight)
{
DataType pivotT = srcData[iLeft];
while (iLeft<iRight)
{
while((iLeft<iRight)&&(pivotT<srcData[iRight]))
{
iRight--;
}
if(iLeft<iRight)
{
srcData[iLeft] = srcData[iRight];
iLeft++;
}
while ((iLeft<iRight)&&(srcData[iLeft]<pivotT))
{
iLeft++;
}
if(iLeft<iRight)
{
srcData[iRight] = srcData[iLeft];
iRight--;
}
}//while
srcData[iLeft] = pivotT;
return iLeft;
}
//【2】快速排序
template<typename DataType>static void QuickSort(DataType srcData[],int iLeft,int iRight)
{
if(iLeft<iRight)
{
int iPos = QuickPartition(srcData,iLeft,iRight);//【1】选择一个基准,进行一次排序
QuickSort(srcData,iLeft,iPos-1); //【2】对左边的子序列进行【快速排序】
QuickSort(srcData,iPos+1,iRight); //【3】对右边的子序列进行【快速排序】
}
}
//===============================================================================================================================
//=========================================================【选择排序】==========================================================
//===============================================================================================================================
/***********************************************************************************************************************
函数原型:
template<typename DataType>static void SelectSort(DataType srcData[],int iLength)
函数说明:
【排序算法6】---------【简单选择排序】
性能分析:
【1】【空间效率】:仅用常数个辅助单元,故空间效率为O(1)
【2】【时间效率】:从下面的代码中不难看出,简单选择排序过程中,元素移动的操作次数很少,不会超过3(n-1),最好的情况
是移动0次,此时对应的表已经有序;但元素间比较的次数与序列的初始状态无关,始终是n(n-1)/2次,所以
时间复杂度为O(n*n)
【3】【简单选择排序】:是一个不稳定的排序方法。
***********************************************************************************************************************/
template<typename DataType>static void SelectSort(DataType srcData[],int iLenght)
{
int iMin = 0; //【1】将选出来的最小元素的下标存放在iMin中
DataType tempT;
for(int i=0;i<iLenght;i++)
{
iMin = i;
for(int j=0;j<iLenght;j++)
{
if(srcData[j]<srcData[iMin])
{
iMin = j;
}
}//for j
if(iMin!=i)
{
tempT = srcData[i];
srcData[i] = srcData[iMin];
srcData[iMin] = tempT;
}
}//for i
}
/***********************************************************************************************************************
函数原型:
template<typename DataType>static void SelectSort(DataType srcData[],int iLength)
函数说明:
【排序算法7】---------【堆排序】
性能分析:
***********************************************************************************************************************/
/***********************************************************************************************************************
模块说明:
【重建堆】----------【调整堆】
***********************************************************************************************************************/
template<typename DataType>static void HeapAdjust(DataType srcData[],int iRootNum,int iLength)
{
int iLeftChild = 2*iRootNum; //【1】iRootNum的左孩子结点序号
int iRighChild = 2*iRootNum+1; //【2】iRootNum的右孩子结点序号
int iMax = iRootNum; //【3】临时变量,存储大根堆的根节点序号(相对来说)
if(iRootNum<=iLength/2) //【4】如果iRootNum是叶子结点,就不用调整
{
if((iLeftChild<=iLength)&&(srcData[iLeftChild]>srcData[iMax]))
{
iMax = iLeftChild;
}
if((iRighChild<=iLength)&&(srcData[iRighChild]>srcData[iMax]))
{
iMax = iRighChild;
}
if(iMax!=iRootNum)
{
std::swap(srcData[iRootNum],srcData[iMax]);
HeapAdjust<DataType>(srcData,iMax,iLength); //【5】避免调整之后以iMax为根节点的堆不是大根堆
}
}
}
/***********************************************************************************************************************
模块说明:
【建初堆】
***********************************************************************************************************************/
template<typename DataType>void BuildHeap(DataType srcData[],int iLength)
{
for(int iNonLeafNodeNum = iLength/2;iNonLeafNodeNum>=1;iNonLeafNodeNum--)
{
HeapAdjust<DataType>(srcData,iNonLeafNodeNum,iLength);
}
}
/***********************************************************************************************************************
模块说明:
【堆排序】
***********************************************************************************************************************/
template<typename DataType>void HeapSort(DataType srcData[],int iLength)
{
BuildHeap<DataType>(srcData,iLength);
for(int i=iLength;i>=1;i--)
{
std::swap(srcData[1],srcData[i]);
HeapAdjust<DataType>(srcData,1,i-1);
}
}
/****************************************************【Main函数】******************************************************
模块说明:
控制台应用程序的入口点
***********************************************************************************************************************/
int main(int argc,char* argv[])
{
std::cout<<"===========================================【排序之前】============================================"<<std::endl;
for(int i=0;i<ARRAY_LENTGTH;i++)
{
std::cout<<srcData[i]<<" ";
}
std::cout<<std::endl;
//BubbleSort<ElemType>(srcData,ARRAY_LENTGTH);
//QuickSort(srcData,0,ARRAY_LENTGTH-1);
//SelectSort<ElemType>(srcData,ARRAY_LENTGTH);
HeapSort<ElemType>(srcData,ARRAY_LENTGTH-1);
std::cout<<"===========================================【排序之后】============================================"<<std::endl;
for(int i=0;i<ARRAY_LENTGTH;i++)
{
std::cout<<srcData[i]<<" ";
}
std::cout<<std::endl;
std::system("pause");
return 0;
}
【Data_Structure笔记14】【笔试】之【所有排序算法】
最新推荐文章于 2024-07-31 12:59:23 发布