#pragma once//函数文件

#include<iostream>
#include<assert.h>
using namespace std;

void InsertSort(int* a,size_t size)
{
	assert(a);

	size_t i = 0;
	
	for (; i < size - 1; ++i)
	{
		int end = i;
		int next = i+1;
		while (end>=0)
		{
			if (a[end]>a[next])
			{
				swap(a[end], a[next]);
				next = end;
			}
			--end;
		}
	}
}

void ShellSort(int* a, size_t size)//希尔排序
{
	assert(a);

	size_t i = 0;
	size_t gap = size;//gap 为 插入间隔
	while (gap > 1)//间隔不为1 循环
	{
		gap = gap / 3 + 1;
		for (i=0; i < size - gap; ++i) //从1 位起 依次插入 之前有序的序列
		{
			int end = i; //end表示有序序列末尾
			size_t next = i + gap;//第一个要插入的为末尾加间隔
			while (end >= 0&&next<size)
			{
				if (a[end]>a[next])
				{
					swap(a[end], a[next]);
					next = end;
				}
				end-=gap;
			}
		}
	}
}

void QuickSort( int* a,int left,int right)//快慢指针的快排
{
	assert(a);

	if (left >= right)
		return;
	int key = a[left];
	int start = left;
	int end = right;
	while (end>start)
	{
		if (a[end] < key)
			++start;
		else
			--end;
		if (a[end]< key&&a[start] > key)
			swap(a[end],a[start]);

	}
	if (a[left] > a[start])
		swap(a[left], a[start]);
	QuickSort(a, left, start - 1);
	QuickSort(a, start+1, right);
}

void QuickSort_PC(int* a,size_t left,size_t right)//前后指针快排
{
	assert(a);

	size_t prev=left;
	size_t cur =left;
	size_t key = left;
	for (; cur<=right;)
	{
		if (a[cur] < a[key]&&prev<cur)
		{
			if (a[prev]>a[key])
				swap(a[cur], a[prev]);
			else
				++prev;
		}
		else
			++cur;
	}
	if (a[prev] < a[key])
		swap(a[prev], a[key]);
	if (left < right)
	{
		QuickSort_PC(a,  left,  prev);
		QuickSort_PC(a, prev+1, right);

	}

}

int MaxDigit(int *a, size_t size)
{
	int count = 1;
	int max = 10;
	for (size_t i = 0; i < size; ++i)
	{
		while(a[i] >= max)
		{
			max *= 10;
			++count;
		}
	}
	return count;
}

//基数排序 只能正整数(利用数组下标特性)
void  RadixSort(int * a,size_t size)
{
	assert(a);

	int* count = new int[10];	//生成每一位 的值得数组0--9 计数
	int* bucket = new int[size];  //生成储存排过一次序后的元素 数组
	int maxDigit = MaxDigit(a, size);//计算最大数 位数
	int digit = 1;//循环计数变量
	while (maxDigit >=digit ) //从个位到最高位 排序次数
	{
		for (size_t i = 0; i < size; ++i)
		{
			bucket[i] = 0; //将数组制零
		}
		for (int i = 0; i < 10; ++i)
		{
			count[i] = 0;//将桶的计数 制零
		}
		for (size_t i = 0; i < size; ++i)
		{
			int j = (a[i] / (int)pow(10, digit - 1)) % 10;//计算每一位的值
			++count[j];//计数自加
 		}
		for (size_t i = 1; i <10; ++i)
		{
			count[i] = count[i] + count[i - 1];//计算根据每一位排序后第一个元素 在bucket[]中的起始位置
											
		}
		int index=0; //计算下标
		int k = 0; //当某位 为0时,下标的计数
		for (size_t i = 0; i <size; ++i)
		{
			
			index = (a[i] / (int)pow(10, digit - 1)) % 10;
			if (index == 0)
				bucket[k++] = a[i];
			else
				bucket[count[index-1]++]=a[i];//某位 数值不为0,第一个元素位置count[下标-1]
		}
		memmove(a, bucket, size*sizeof(int)); //将排过序的数组 拷贝进 原数组
		++digit; //计数器自加
	}
	
}

void PartitionMerger(int* dst, int* src , size_t start, size_t mid, size_t end)
{//

	size_t i = start, j = mid+1, k = start;//mid指向后半区间第一个
	for (; i <=mid&&j <=end;)//按大小依次将src中区间内数据写去dst
	{
		if (src[i]>src[j])
		{
			dst[k] = src[j];
			++j;	
		}
		else
		{
			dst[k] = src[i];
			++i;
		}
		++k;
	}

	while (i <=mid) //剩下的继续写去
	{
		dst[k] = src[i];
		++i;
		++k;
	}
	while (j <=end)
	{
		dst[k] = src[j];
		++j;
		++k;
	}
	memmove(src+start, dst+start, (end - start+1)*4);//将一归并排序区间内的数据写入src src为临时数组
}

void mergerSort(int* dst,int* src,size_t start,size_t end)
{
	size_t mid = start + (end - start) / 2;	
	if (end-start>1)//区间个数大于2  分小区间
	{
		mergerSort(dst,src,start,mid);
		mergerSort(dst,src,mid+1,end);	
	}
	PartitionMerger(dst, src, start, mid, end);//单趟排序
}

void MergerSort(int* a, size_t start, size_t end)//封装 归并排序
{
	assert(a);
	
	int* tmp = new int[end - start + 1];//储存区间归并排序的结果
	mergerSort( tmp,a  , start, end);//归并排序
	delete tmp;

}

void Print(int* a,size_t size)
{
	for (size_t i = 0; i < size; ++i)
	{
		cout << a[i] << ' ';
	}
	cout << endl; 
}
//主函数  测试用例
#include"allsort.hpp"

void test()
{
	int a[10] = { 5, 9, 6, 4, 7, 8, 3, 1, 2, 0 };
	InsertSort(a, 10);
	Print(a, 10);
}

void test1()
{
	int a[10] = { 5, 9, 6, 4, 7, 8, 3, 1, 2, 0 };
	ShellSort(a, 10);
	Print(a, 10);
}
void test2()
{
	int a[13] = { 5, 9, 6,5,1,2, 4, 7, 8, 3, 1, 2, 0 };
	QuickSort(a, 0,12);
	Print(a, 13);
}
void test3()
{
	int a[13] = { 5, 9, 6, 5, 1, 2, 4, 7, 8, 3, 1, 2, 0 };
	QuickSort_PC(a, 0, 12);
	Print(a, 13);
}

void test4()
{
	int a[17] = { 15, 39, 26,35, 51, 42, 44, 77, 68, 43, 51, 82, 90 ,100,999,1001,199563};
	RadixSort(a,  17);
	Print(a, 17);
}

void test5()
{
	int a[11] = { 1, 9, 6, 5, 1, 2, 4, 7, 8, 3, 3 };
	MergerSort(a, 0, 10);
	Print(a, 11);
}

int main()
{
	test();
	test1();
	test2();
	test3();
	test4();
	test5();
	return 0;
}