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

															// 测试数据集,0单元未用
int IA[9]={0,58,40,65,97,87,8,17,58};						// 直接插入、折半插入
int SA[11]={0,58,40,65,97,87,8,17,58,46,60};				// 希尔
int BA[9]={0,58,40,65,97,87,8,17,58};						// 冒泡
int QA[9]={0,58,35,65,97,87,8,17,58};						// 快速
int SSA[9]={0,58,35,25,97,87,8,58,17};						// 简单选择排序
int HA[9]={0,38,25,16,36,18,32,28,50};						// 堆排序
int EA1[8]={0,58,40,25,87,8,58,17};							// 归并
int EA2[9]={0,8,4,5,2,6,3,7,9};								// 递归归并
int RA[9]={0,769,763,63,249,243,545,281,89};				// 基数排序



void CopyData(int a[],int n, int R[])						// 数据后移一个单元，从1单元开始 
{
	for(int i=1;i<=n;i++)
		R[i]=a[i];
}

void DispData(int R[], int n)								// 数据显示
{
	int i;
	for(i=1;i<=n;i++)
		cout<<R[i]<<'\t';
	cout<<endl;
}

// 算法8.1													直接插入排序
void InsertSort(int R[], int n)
{
	int i, j;
	for(i=2; i<=n; i++)										// 从第2个元素开始
	{
		if(R[i-1]>R[i])										// 1.如果R[i-1]>R[i]
		{
			R[0]=R[i];										// 1.1 R[i]复制为监视哨
			R[i]=R[i-1];									// 1.2 R[i]后移
			for(j=i-2;R[j]>R[0];--j)						// 1.3 j从i-2开始，如果R[j]>R[0]， R[j]后移，j--						
				R[j+1]=R[j];								// 1.4 插入R[i]，i++
			R[j+1]=R[0];
		}													
		cout<<" 第 "<<i-1<<" 趟 \t";						// 显示每趟排序结果
		DispData(R,n);
	}														// 2.否则，i++，进入下一趟
}

//算法8.2													折半插入排序
void BInsertSort(int R[],int n)
{
	int i,j,m;
	int low,high;
	for(i=2; i<=n; i++)										// n个记录，进行n-1趟										
	{
		R[0]=R[i];											// 1.保存R[i]
		low=1;												// 2.用折半查找方法，找插入点
		high=i-1;											// 2.1 设置查找范围的下界和上界
		while(low<=high)									// 2.2 只要low<=high
		{
			m=(low+high)/2;									// 2.2.1计算中间位置m
			if(R[m]>R[i])  high=m-1;						// 2.2.2 R[m]>R[0]，调整查询上界
			else low=m+1;									//     否则，调整查找下界
		}												// 3.插入点high+1后元素移动
		for(j=i-1;j>=high+1;--j)							// 3.1 R[i-1]～R[high+1]依次后移
			R[j+1]=R[j];									// 3.2 R[i]复制到R[high+1]
		R[high+1]=R[0];
		cout<<" 第 "<<i-1<<" 趟 \t";						// 显示每趟排序结果
		DispData(R,n);										 
	}
}

//算法8.3													 希尔排序

void ShellInsert(int R[],int n,int dk)						// 增量为dk的一趟希尔排序
{
	int i,j;
	for(i=dk+1;i<=n;++i)									
		if(R[i]<R[i-dk])									// 通过下标间距控制一起插入排序的元素，d组同时进行。
		{
			R[0]=R[i];
			for(j=i-dk;j>0 && (R[0]<R[j]); j-=dk)
				R[j+dk]=R[j];
			R[j+dk]=R[0];
		}
}

void ShellSort(int R[],int n,int d[],int t)
{
	int k;
	for(k=0;k<t;k++)										// t个增量
	{
		ShellInsert(R,n,d[k]);								// 进行t趟
		cout<<" 第 "<<k+1<<" 趟 \t";							// 显示每趟排序结果
		DispData(R,n);
	}
}


//算法8.4													冒泡排序
void Bubble_Sort(int R[],int n)
{
	int i,j,temp;
	bool exchange;
	for(i=1,exchange=true;i<n && exchange; i++)				// 增量为dk的一趟希尔排序操作结束。
	{														// 一趟排序工作如下：
		exchange=false;										// 1.设置交换标志初值为无交换
		for(j=1;j<=n-i;j++)									// 2.从表首开始两两比较
		{
			if (R[j]>R[j+1])								// 2.1相邻元素逆序，互换位置
			{
				temp=R[j],R[j]=R[j+1],R[j+1]=temp;			// R[j]<-->R[j+1]
				exchange=true;								// 2.2 交换标志改为true
			}
		}
		cout<<" 第 "<<i<<" 趟 \t";								// 显示每趟排序结果
		DispData(R,n);
	}
}

//算法8.5													一次划分
int Partition(int R[],int low,int high) 
{
	int pivot;
	pivot=R[low];											// 1. 第1个记录为枢轴
	while(low<high)											// 2. 扫描完所有记录，退出循环
	{
		while(low<high && R[high]>=pivot)                   // 2.1 从高端做起，
		    --high;											// 2.1.1 比枢轴大，位置不动
		R[low]=R[high];										// 2.1.2 比枢轴小，记录移到低端
		while(low <high && R[low]<=pivot)					// 2.2 转到低端，
			++low;											// 2.2.1 比枢轴小，位置不动
		R[high]=R[low];										// 2.2.2 比枢轴大，记录移到高端
		cout<<endl;											// 转至高端
	}
	R[low]=pivot;											// 3. 扫描结束，枢轴记录定位
    return low;												// 4. 返回枢轴位置。
}

//算法8.6													快速排序递归算法
void QSort(int R[],int low,int high)						// 对R[n]进行快速排序
{
	int pivoitloc;
	if(low<high)											// 序列长度大于1，//进行下列操作
	{
		pivoitloc=Partition(R,low,high);					// 1. 一次划分
		cout<<"枢轴元素："<<R[pivoitloc];					// 轴出各趟枢轴元素
		QSort(R,low,pivoitloc-1);							// 2. 对低子序列递归排序
		QSort(R,pivoitloc+1,high);							// 3. 对高子序列递归排序
	}
}

//算法8.7													简单选择排序
void SelectSort(int R[],int n)//对R[n]进行简单选择排序
{
	int i,j,t,mink;
	for(i=1;i<n;++i)										// 共需n-1趟，每一趟操作如下：
	{
		mink=i;												// 1.查找最小关键码记录号mink
		for(j=i+1;j<=n;++j)
			if(R[j]<R[mink])
				mink=j;
		if(mink!=i)											// 2.如果最小记录不是第i个
		{
			t=R[i];R[i]=R[mink];R[mink]=t;					// 3.R[i]←→R[mink]
		}
        cout<<" 第 "<<i<<" 趟 \t";							// 显示每趟排序结果
		DispData(R,n);
	}
}


//算法8.8													一次筛选
void HeapAdjust(int R[],int s,int n)						//将R[s..n]调整为以R[s]为根的大根堆

{
	int j;
	R[0]=R[s];												// 1.复制R[s]，让出R[s]空间
	for(j=2*s;j<=n;j=2*s)									// 2.一次筛选
	{
		if(j<n && R[j]<R[j+1])								// 2.1比较子树根的两个孩子，取较大者
			j++;
		if(R[0]>R[j])										// 2.2子树根大于较大者，无需记录移动
			break;
        R[s]=R[j];											// 2.3 否则，R[j]为子树根
		s=j;												// 2.4 考量下一级子树，												
	}														
	R[s]=R[0];												// R[s]插入到合适位置
}

//算法8.9													建堆
void CreateHeap(int R[],int n)								//把无序序列R[1..n]建成大根堆
{
	int i;
	for(i=n/2;i>0;--i)										// 从首个非叶结点开始
	{
		HeapAdjust(R,i,n);									// 反复调用HeapAdjust，逐个调整。
	}
	cout<<"    堆 ：\t";									// 输出堆
	DispData(R,n);
}

//算法8.10													堆排序
void HeapSort(int R[],int n)
{
	int i,t;
	CreateHeap(R,n);										// 建堆
	for(i=1;i<n;i++)
	{
		t=R[1];R[1]=R[n-i+1];R[n-i+1]=t;					// 堆顶与堆尾元素互换位置
		cout<<" 第 "<<i<<" 趟 \t";							// 显示每趟排序结果
		DispData(R,n);
		HeapAdjust(R,1,n-i);								// 调整成堆
		
	}
}



//算法8.11													   两个有序列合并
void Merge(int R[],int s, int m, int t)						// 两个有序序列R[s..m]、R[m+1..t]合并一个有序序列
{
	int *R1;												// 1. 初始化
	int i,j,n,k;
	n=t+1;         //1.1辅助数组临存归并结果
	R1=new int[n];											// 1.2 设3个工作指针i、j、k分别指向R[s]、R[m+1]、R1[]首元处
	i=s;
	j=m+1;
	k=s;
	while(i<=m && j<=t)										// 2.两个序列合并：2.1两个序列均不空
	{
		if(R[i]<=R[j])
			R1[k++]=R[i++];
		else
			R1[k++]=R[j++];
	}
	while(i<=m)												// 2.2若第1个子序列未处理完,R[m+1..t]为剩余记录
		R1[k++]=R[i++];
	while(j<=t)												// 2.3若第2个子序列未处理完，将其剩余部分复制到R1
		R1[k++]=R[j++];
	for(k=s,i=s;i<=t;k++,i++)								// 3.将R1复制到R[s..t]中
		R[i]=R1[k];
	delete R1;												// 释放R1。
}


//算法8.12													一趟归并
void MergePass(int R[],int n,int len)
{
	int i=1;												// 序列下标从1开始
	while(i+2*len-1<=n)										// 等长子序列合并
	{
		Merge(R,i,i+len-1,i+2*len-1);
		i+=2*len;
	}
	if(i+len-1<n)											// 不等长子序列
		Merge(R,i,i+len-1,n);
}


//算法8.13													 2-路归并算法
void MergeSort(int R[],int n)
{
	int len;
	for(len=1;len<=n;len=len*2)								// 初始子序列长度为1
	{
		MergePass(R,n,len);									// 子序列合并
		cout<<" 第 "<<len/2+1<<" 趟 \t";					// 显示每趟排序结果
		DispData(R,n);
	}
}

//算法8.14													2-路归并递归算法
void MSort(int R[],int s,int t)
{
	int m;													//1.待排序记录只有1个，递归结束
	if(s<t)
	{
		m=(s+t)/2;											//2. 序列对半分
	    MSort(R,s,m);										//3. 递归归并前半个子序列
	    MSort(R,m+1,t);										//4. 递归归并后半个子序列
	    Merge(R,s,m,t);										//5. 左、右两个子序列归并
	}
}

void MergeSort1(int R[], int n)
{
	MSort(R,1,n);											// 初次调用
}



struct RNode												// 多关键字结点
{
	int keys[3];											// 设关键字数为d=3
	struct RNode *next;
};


void CreateDL(RNode *&L,int R[],int n)						// 尾插法建无头结点单链表，存储待排序记录
{
	int i;
	RNode *p,*rr;
	for(i=1;i<=n;i++)
	{
		p=new RNode;
		//cout<<"R[i]"<<R[i]<<'\t';
		p->keys[0]=R[i]/100;								// 百位
		p->keys[1]=R[i]%100/10;								// 十位
		p->keys[2]=R[i]%100%10;								// 个位
		p->next=NULL;
		if (i==1)											// 首元结点
		{
			L=p;
			rr=L;
		}
		else												// 非首元结点
		{
			rr->next=p;
			rr=p;			
		}
		cout<<endl;
	}
}

void DispDL(RNode *L)
{
	int d;
	RNode *p;
	p=L;
	while(p!=NULL)
	{
		for(d=0;d<3;d++)
			cout<<p->keys[d];
		cout<<'\t';
		p=p->next;
	}
	cout<<endl;
}
		
//算法8.15													基数排序
void RadixSort(RNode *&L,int r,int d)						// r进制数、d位数的基排序
{
	int i,j,k;
	RNode *h[10],*t[10],*T;									// 10进制数，建立10个队列
	for(i=d-1;i>=0;i--)										// d个数位d个关键字，d趟
	{														// 每一趟
		for(j=0;j<r;j++)									// 1.队列初始化
			h[j]=t[j]=NULL;									
		while(L!=NULL)										// 2.扫描序列列表，进行分								
		{
			k=L->keys[i];									// 2.1第i个子关键字为k则入第k个队列
			if(h[k]==NULL)									// 2.1.1首元结点， 
			{
				h[k]=L;t[k]=L;								// 队尾指向队头
			}
			else											// 2.1.2非首元结点，
			{
				t[k]->next=L; t[k]=L;						// 入队尾
			}
			L=L->next;										// 2.2 取一下待排序记录									
		}
		L=NULL;												// 收集
		for(j=0;j<r;j++)									// 3.1 r个队列，尾-首相连									
		{
			if(h[j]!=NULL)									// 3.1.2首元结点
			{
				if(L==NULL)									// 队尾指向队头								
				{
					L=h[j];T=t[j];							
				}
			    else										// 3.1.3 非首元结点，
				{
				    T->next=h[j];T=t[j];					// 首尾相接
				}
			}
		}
		T->next=NULL;										 // 尾结点，next为空
		cout<<" 第 "<<d-i<<" 趟 "<<'\t';
		DispDL(L);
	}
}

void dispmenu()
{
	cout<<"* 主  菜  单  *"<<endl;
	cout<<"---------------"<<endl;
	cout<<"* 插  入  排  序 * "<<endl
	    <<"  1 直接插入排序"<<endl
	    <<"  2 折半插入排序"<<endl
	    <<"  3 希尔排序"<<endl
	    <<endl;
	cout<<"* 交  换  排  序 *"<<endl
	    <<"  4 起泡排序"<<endl
	    <<"  5 快速排序"<<endl
	    <<endl;
	cout<<"* 选   择   排   序 *"<<endl
	    <<"  6 简单选择排序"<<endl
	    <<"  7 堆排序"<<endl
	    <<endl;
	cout<<"  8 归并排序"<<endl
	    <<"  9 基数排序"<<endl   
	    <<"  0 退出程序"<<endl;
	cout<<"请选择主菜单：";
}


																// 主函数
int main()
{
	int n;
	system("cls");												// 清屏
    
	int choice;
    do
	{
		dispmenu();												// 显示主菜单
		cout<<endl;
		cout<<"Enter choice(1~10,0 退出):";
		cin>>choice;
		switch(choice)
		{
			case 1:												// 直接插入排序
			{
                cout<<"直接插入排序"<<endl;
				cout<<endl;
				n=8;
				int R[9];
				CopyData(IA,n,R);								// IA[]-->R
				cout<<"初始序列"<<'\t';							// 显示初始序列
                DispData(R,n);
				InsertSort(R,n);								// 直接插入排序
				;
				break;
			}
		     case 2:											//	折半插入排序 
			 {
				cout<<"折半插入排序"<<endl;
				cout<<endl;
				n=8;
				int R[9];
				CopyData(IA,n,R);								// IA[]-->R
				cout<<"初始序列"<<'\t';								// 显示初始序列
				DispData(R,n);
				BInsertSort(R,n);								//	折半插入排序
				cout<<endl;
				break;
			 }
			case 3:												// 希尔排序
			{
				cout<<"希尔排序"<<endl;
				cout<<endl;
				int d[3]={5,3,1};								// d值
				 n=10;
				 int R[11];
                 CopyData(SA,n,R);								// SA[]-->R[]
			     cout<<"初始序列"<<'\t'; 
				 DispData(R,n);									// 显示初始序列
				 ShellSort(R,n,d,3);							// 希尔排序
				 break;	
			}
			 case 4:											// 冒泡排序
			 {
                cout<<"冒泡排序"<<endl;
				cout<<endl;
				n=8;
				int R[9];
				CopyData(BA,n,R);								// BA[]-->R[]
				cout<<"初始序列"<<'\t';							// 显示初始序列
                DispData(R,n);
				Bubble_Sort(R,n);								// 冒泡排序
				break;
			 }
              case 5:											// 快速排序
			{
				cout<<"快速排序"<<endl;
				cout<<endl;
				//n=sizeof(QA)/sizeof(QA[0]);
				n=8;
				int R[9];
            	CopyData(QA,n,R);								// QA[]-->R[]
				cout<<"初始序列"<<'\t';								// 显示初始序列
                DispData(R,n);
				QSort(R,1,n);									// 快速排序
				cout<<endl;
				cout<<"有序序列\t";
                DispData(R,n);									// 排序结果
				break;
			}
			 case 6:											// 简单选择排序
			{
				cout<<"简单选择排序"<<endl;
				cout<<endl;
				n=8;
				int R[9];
                CopyData(SSA,n,R);								// SSA[]-->R[]
				cout<<"初始序列"<<'\t';							// 显示初始序列
                DispData(R,n);
			    SelectSort(R,n);								// 简单选择排序
				break;
			}
			 case 7:											// 堆排序
			{
				cout<<"堆排序"<<endl;
				cout<<endl;
				n=8;
				int R[9];
				CopyData(HA,n,R);								// HA[]-->R[]
				cout<<"初始序列"<<'\t';							// 显示初始序列
                DispData(R,n); 
				HeapSort(R,n);									// 堆排序
				cout<<endl;
				break;
			}
			 case 8:											// 二路归并排序
			{
				int n1,n2;
				cout<<endl; 
				cout<<"归并排序（非递归）"<<endl;				// 二路归非递归并排序
				cout<<endl;
				n1=7;
				int R1[8];
				CopyData(EA1,n1,R1);							// EA1-->R1
				cout<<"初始序列"<<'\t';							// 显示初始序列
                DispData(R1,n1);
				MergeSort(R1,n1);								// 二路归递归并排序
				cout<<"归并排序（递归）"<<endl;
				cout<<endl;
				n2=8;
				int R2[9];
				CopyData(EA2,n2,R2);							// EA2-->R2
				cout<<"初始序列"<<'\t';							// 显示初始序列
                DispData(R2,n2);
				MergeSort1(R2,n2);
				cout<<"有序序列\t";
                DispData(R2,n2);								// 排序结果
				break;
			}
             case 9:											// 基数排序
			{
				int r,d;
				r=10;											// 十进制数
				d=3;											// 3个关键字
				RNode *L;										// 链式存储，无头结点
				L=NULL;											// 空表
				cout<<"基排序"<<endl;
				cout<<endl;
				n=8;
				int R[9];
				CopyData(RA,n,R);								// RA-->R
				cout<<"测试数据:";
				DispData(R,n);									// 显示初始序列
				CreateDL(L,R,n);								// 创建链表
				cout<<"初始序列"<<'\t';							// 显示链表
                DispDL(L);
				RadixSort(L,r,d);								// 基数排序
				cout<<"有序序列\t";								// 显示排序结果
                DispDL(L);
				break;
			}
			 
  			case 0://退出
                ;
				cout<<"结束运行"<<endl;
                break;
			default://非法选择
				cout<<"Invalid choice\n";
				break;
			}
	}while(choice!=0);
    
	return 0;
}




