#include <IOSTREAM>

#include <VECTOR>

#include <algorithm>

#include <iostream>  

#include <bitset>  

#include <string>  


using namespace std;

  

// a和b数值进行交换 

 Swap(int& a,int& b) {

if (a==b) return;

int k=a;

a=b;

b=k;

}

/*******************************1、冒泡排序****************************/

//原理:依次比较相邻的2个数,将比较小的数放在前面,比较大的数放在后面

BubbleSort(int arrNum[], int nSize){

       int i=0;

       int j=0;

       int n=nSize; //数组含有元素的个数

//如果数组个数少于2个,没有必要比较,直接退出

      if(n<=1) return;

      for (i=0;i<n;i++){

 //n-i-1是每轮比较的最大次数;因为下标j+1要小于数组的最大下标,所以还要-1

             for (j=0;j<n-i-1;j++) {

                    Swap(arrNum[j],arrNum[j+1]);

            }

      }

}

/**************************2、选择排序******************************/

//原理:每次从待排序的数据元素中选出最小(或者最大)的一个元素,存放在已排好序列的起始位置(或者末尾位置), 直到全部待排序  

SelectionSort(int arrNum[],int nSize) {

int i=0;

int j=0;

int n=nSize;

if (n<=1) return; 

for (i=0;i<n;i++){

 int pos=i; //pos记录值最小的数组下标位置

 for (j=i;j<n;j++) {

  if (arrNum[pos]>arrNum[j])

   pos=j;

 }

 Swap(arrNum[i],arrNum[pos]);

}

}


/*********************3、直接插入排序******************************/

//原理:是将无序序列中的数据插入到有序的序列中,在遍历无序序列时,首先拿无序序列中的首元素去与有序序列中的每一个元素比较并插入到合适的位置,一直到无序序列中的所有元素插完为止。

InsertionSort(int arrNum[], int nSize) {

int i=0;

int j=0;

int n=nSize;

if (n<=1) return;

for (i=0;i<n;i++){

 for (j=i+1;j<n;j++) {

  Swap(arrNum[i],arrNum[j]);

 }

}

}


/***********************************4、希尔排序***********************/

//原理:是把序列按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量的逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个序列恰好被分为一组,算法便终止。

//分组增量gap=length/2,缩小增量以gap=gap/2

ShellSort(int arrNum[], int nSize) {

int j=0;

int i=0;

int n=nSize;

int gap=n/2;

if (n<=1 || gap<1) return;

while (gap>0){

 for (i=0;i<n/gap;i++) {

  for (j=i+gap;j<n;j=j+gap)  {

   Swap(arrNum[i],arrNum[j]);

  }

 }

 gap=gap/2;

}

}


/****************************5、归并排序******************************/

//原理算法:先把数据组分成一半,再把左边的数组再分一半排序,右边的数组再分一半,一直分到只有2个有序数为至,然后再归并

MergeSort(int arrNum[], int low,int high) {

int i=0;

int j=0;

int k=0;

int n=0;

int half=low+(high-low)/2;

//不能再分的条件,high是当前数组的个数,不是最大元素的下标

if (low>=(high-1)) return;  

//先分

MergeSort(arrNum,low,half);

MergeSort(arrNum,half,high);

//再合

//临时开辟动态数组

n=high-low;

int* pArray=(int*)malloc(n*sizeof(int));

memset(pArray,0,n*sizeof(int));

i=0;

j=low;

k=half;

while(j<half && k<high){

 if (arrNum[j]>arrNum[k])

  pArray[i++]=arrNum[k++];

 else

  pArray[i++]=arrNum[j++];

}

while(j<half)

 pArray[i++]=arrNum[j++];

while(k<high)

 pArray[i++]=arrNum[k++];

for (i=0;i<n;i++)

 arrNum[low++]=pArray[i];

  free(pArray);

}


/*********************6、快速排序*******************************/

//选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小。

//然后,再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

QuickSort(int  arrNum[], int low,int high) {

int i=low;

int j=high-1;

int nBase=arrNum[low];

//递归中止条件

if (i>=j) return;

//基准数选取当前数组区间的第1个元素  

while(true){

 //从后向前扫描,找小于基准数的值,然后放到下标为i的位置  

 while(i<j) {

  if(nBase<=arrNum[j])

   j--;

  else  {

   arrNum[i]=arrNum[j];

   break;

  }

 }

 

 //从前向后扫描,找大于基准数的值,然后放到下标为j的位置

 while(i<j) {

  if(nBase>arrNum[i])

   i++;

  else  {

   arrNum[j]=arrNum[i];

   break;

  }

 }

 if (i==j) {

  arrNum[i++]=nBase;

  break;

 }

}


QuickSort(arrNum,low,i);

QuickSort(arrNum,i,high);

}


//建立大堆

//堆是一种非线性结构,可以把堆看作一个数组,也可以被看作一个完全二叉树,通俗来讲堆其实就是利用完全二叉树的结构来维护的一维数组但堆并不一定是完全二叉树

//按照堆的特点可以把堆分为大顶堆和小顶堆

//大顶堆:每个结点的值都大于或等于其左右孩子结点的值

//小顶堆:每个结点的值都小于或等于其左右孩子结点的值

//二叉数,设深度为h(根节点层数为0),某个父节点为dad,子节点为son,有以下特点:

//满二叉数: 总节点数是:2^(h+1)-1,第k层节点数是:2^k

//完全二叉数:第k层节点数是:2^k

//父和子节点的2个元素序号关系:dad=son*2+1,dad=son*2+2

MaxHeap(int arrNum[], int start,int tail) {

int dad=0;  //存放父节点序号

int son=0;  //存放子节点序号

dad=start;

son=dad*2+1; //左孩子节点


//当有孩子节点时

while(son<=tail){

//当同时存在2个子节点时,先比较2个子节点值的大小,选择值最大的节点

 if (son+1<=tail) {

  if (arrNum[son]<arrNum[son+1])

   son=son+1;

 }


 //如果父节点的值大于子节点(最大值的子节点)时,直接返回

 if (arrNum[dad]>arrNum[son])  return;

 

 //如果父节点的值小于子节点的值时,交换位置

 Swap(arrNum[dad],arrNum[son]);

 //使当前子节点成为父节点,往下继续查找比较建立大堆

 dad=son;

 son=dad*2+1;

}

}

/*************************7、堆排序**********************************/

//原理:堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序,首先简单了解下堆结构

HeapSort(int arrNum[], int nSize) {

int i=0;

int j=0;

int k=0;


//初始化构建一个完全二叉数,方法是:(length/2-1)为最后一个父节点,从当前父节点往下构建大堆,然后循环一直到根节点

i=nSize/2-1;

for (i;i>=0;i--)

 MaxHeap(arrNum,i,nSize-1);


//从最后一个元素开始向上查找,将第一个元素和已经排好的元素前一位交换,

//再重新调整,构建小堆,直到排序完毕

for (i=nSize-1;i>0;i--)

{

 Swap(arrNum[0],arrNum[i]);

 MaxHeap(arrNum,0,i-1);

}

 }


/*************************8、计数排序*****************************/

//一步:找出原数组中元素值最大的,记为max。

//第二步:创建一个新数组count,其长度是max加1,其元素默认值都为0。

//第三步:遍历原数组中的元素,以原数组中的元素作为count数组的索引,以原数组中的元素出现次数作为count数组的元素值。

//第四步:创建结果数组result,起始索引index。

//第五步:遍历count数组,找出其中元素值大于0的元素,将其对应的索引作为元素值填充到result数组中去,每处理一次,count中的该元素值减1,直到该元素值不大于0,依次处理count中剩下的元素。

//第六步: 返回结果数组result?

CountSort(int arrNum[], int nSize) {

int i=0;

int j=0;

int min=0;

int max=0;

int n=0;

int* pArray=NULL;

min=arrNum[0];

max=min;

for (i=1;i<nSize;i++){

 if(min>arrNum[i])

  min=arrNum[i];

 if(max<arrNum[i])

  max=arrNum[i];

}

n=max-min+1;  //准备开辟的动态数组的空间

pArray=new int[n]; //申请动态数组

memset(pArray,0,sizeof(arrNum[0])*n);


//计数排序第1种计算方法

//  for (i=0;i<nSize;i++)

//   pArray[arrNum[i]-min]++;

//  for (j=0,i=0;i<n;i++)

//  {

//   while (pArray[i]-->0)

//    arrNum[j++]=i+min;

//  }

//计数排序第2种计算方法

//需要在创建一个临时数组,和原数组大小一样

int* pArrayTemp=new int[nSize];


//哪个位置有值,标记为1,如果有多个值,每次+1

for (i=0;i<nSize;i++)

 pArray[arrNum[i]-min]++;


//构建计数数组

for (i=1;i<n;i++)

 pArray[i]+=pArray[i-1];

 

//把排序的结果数据临时存放到临时数组pArraytemp中

for (i=0;i<nSize;i++){

 //作为pArray的下标[arrNum[i]-min]

 int index=arrNum[i]-min;

 pArrayTemp[pArray[index]-1]=arrNum[i];

 pArray[index]--;

}

for (i=0;i<nSize;i++)

 arrNum[i]=pArrayTemp[i];

delete[] pArrayTemp;

pArrayTemp=NULL;

delete[] pArray; //释放动态数组空间

pArray=NULL;

}


/***************************9、桶排序**********************************/

//原理:桶排序是计数排序的扩展版本,计数排序可以看成每个桶只存储相同元素,而桶排序每个桶存储一定范围的元素,通过映射函数,将待排序数组中的元素映射到各个对应的桶中,

//对每个桶中的元素进行排序,最后将非空桶中的元素逐个放入原序列中。

BucketSort(int arrNum[], int nSize) {

int i=0;

int j=0;

int n=0;  //记录桶的个数

int max=arrNum[0];

int min=arrNum[0];

//确认桶的个数,公式: (最大值-最小值)/数组长度

for (i=1;i<nSize;i++){

 if (arrNum[i]<min)

  min=arrNum[i];

 if (arrNum[i]>max)

  max=arrNum[i];

}

n=(max-min)/nSize+1;  //桶的个数

vector<int> * pVector=new vector<int>[n];

 

for(i=0;i<n;i++){

 vector<int> v;

 pVector[i]=v;

}

for(i=0;i<nSize;i++){

 int index=(arrNum[i]-min)/nSize;

 pVector[index].push_back(arrNum[i]);

}

for(i=0;i<n;i++){

 if (pVector[i].size()>0)

   sort(pVector[i].begin(),pVector[i].end());

}

for (j=0,i=0;i<n;i++){

 if(pVector[i].size()>0) {

  vector<int>::iterator it=pVector[i].begin();

    for(it;it!=pVector[i].end();++it)  {

   arrNum[j++]=*it;

  }

 }

}

delete[] pVector;

pVector=NULL;

}


/***************************10、基数排序*************************/

//它是这样实现的:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

RadixSort(int arrNum[], int nSize) {

int i=0;

int j=0;

int n=0; //记录循环次数

int arrCount[10]={0}; //记录每个数当前位的数字的数组

int nRadix=0;

int* pArray=NULL;

//获取数组中最大的数值  

for (i=0;i<nSize;i++)

 n=(arrNum[i]>n)?arrNum[i]:n;


//获取最大数的位数

i=n,n=0;

while(i>0){

 i=i/10;

 n++;

}

pArray=new int[nSize];

i=0,nRadix=1;

while(i<n){  

 for (j=0;j<nSize;j++) {

  int index=(arrNum[j]/nRadix)%10; //获取当前位的数字

  arrCount[index]++;

 }

 for (j=1;j<10;j++) {

  arrCount[j]+=arrCount[j-1];

 }

 memset(pArray,0,sizeof(int)*nSize);

 for (j=nSize-1;j>=0;j--) {

  int index=(arrNum[j]/nRadix)%10; //获取当前位的数字

  pArray[arrCount[index]-1]=arrNum[j];

  arrCount[index]--;

 }

 for (j=0;j<nSize;j++) {

  arrNum[j]=pArray[j];

 }

 memset(arrCount,0,40);

 nRadix=nRadix*10;

 i++;

}

  delete[] pArray;

}