C++实现各种排序算法

来源:互联网 发布:windows切换苹果系统 编辑:程序博客网 时间:2024/04/28 21:11
//各种排序算法
#include"stack.h"
//插入排序(直接插入排序和希尔排序)
//直接插入排序
//正确的swap函数应该像下面那样写,否则无法实现交换
//对于数组使用这个函数,swap(a[low], a[high])
void swap(int *a, int *b)  
{  
int tmp = *a;  
*a = *b;  
*b = tmp;  
}  
void print(int num[],int length)
{
if(num!=NULL&&length>0)
{
for(int i=0;i<length;i++)
{
cout<<num[i]<<" ";
}
cout<<endl;
}
}
void insertsort(int num[],int length)
{
if(num==NULL||length<=0)
cout<<"数组为空"<<endl;
else
{
for(int i=1;i<length;i++)
{
int temp=num[i];
int j=i-1;
while(j>=0&&temp<num[j])
{
num[j+1]=num[j];
j--;
}
num[j+1]=temp;
}
}
}
//希尔排序
void shellsort(int num[],int length)
{
int k=length/2;//步长
if(num==NULL||length<=0)
cout<<"数组为空"<<endl;
else
{
while(k>=1)
{
for(int i=k;i<length;i++)
{
int temp=num[i];
int j=i-k;
while(j>=0&&temp<num[j])
{
num[j+k]=num[j];
j=j-k;
}
num[j+k]=temp;
}
k/=2;
}
}
}
//选择排序(直接选择和堆排序)
//直接选择排序
void selectsort(int num[],int length)
{
if(num!=NULL&&length>0)
{
for(int i=0;i<length;i++)
{
int index=i;
for(int j=i+1;j<length;j++)
{
if(num[j]<num[index])
index=j;
}
if(index!=i)
{
int temp=num[i];
num[i]=num[index];
num[index]=temp;
}
}
}
}
//堆排序
//采用最大堆
void maxheapify(int num[],int i,int size)
{
int left=2*i+1;int right=2*i+2;int largest=i;
if(left<=size&&num[left]>num[i])
largest=left;
if(right<=size&&num[right]>num[largest])
largest=right;
if(largest!=i)
{
int temp=num[i];
num[i]=num[largest];
num[largest]=temp;
maxheapify(num,largest,size);//避免调整之后以max为父节点的子树不是堆 
}
}
void buildmaxheap(int num[],int size)
{
for(int i=(size-1)/2;i>=0;i--)//注意这里需要size-1
maxheapify(num,i,size);//必须从最后一个开始往前推
}
void heapsort(int num[],int size)
{
buildmaxheap(num,size);
for(int i=size-1;i>=0;i--)
{
int temp=num[0];//注意这里是数组最后一个元素与数组首元素交换也就是num[size-1]与num[0]
num[0]=num[i];
num[i]=temp;
maxheapify(num,0,i-1);//注意首元素标号是0
}
}
//交换排序(冒泡排序和快速排序)
//冒泡排序
void bubblesort(int num[],int size)
{
if(num!=NULL&&size>0)
{
for(int i=0;i<size-1;i++)//注意这里需要是size-1,否则下面size-i-1就会超过范围了,
for(int j=0;j<size-i-1;j++) //注意这里是size-i-1.不减去1。j+1就会超过范围
{
if(num[j]>num[j+1])
{
int temp=num[j];
num[j]=num[j+1];
num[j+1]=temp;
}
}
}
}
//双向冒泡排序(鸡尾酒排序)
void bubblesort1(int num[],int size)
{
if(num!=NULL&&size>0)
{
int high=size-1;
int low=0;
while(low<high)
{
for(int i=low;i<high;i++)
{
if(num[i]>num[i+1])
{
int temp=num[i];
num[i]=num[i+1];
num[i+1]=temp;
}
}
--high;
for(int j=high;j>low;j--)
{
if(num[j]<num[j-1])
{
int temp=num[j];
num[j]=num[j-1];
num[j-1]=temp;
}
}
++low;
}
}
}




//快速排序
//方法1


int partition(int num[],int length,int start,int end)
{
if(num!=NULL&&length>=0&&start>=0&&end<=length&&end>=start)
{
int key=num[end];
int i=start-1;
for(int j=start;j<end;j++)
{
if(num[j]<key)
{
i++;
int temp=num[i];
num[i]=num[j];
num[j]=temp;
}
}
i++;
int temp=num[i];
num[i]=num[end];
num[end]=temp;
return i;
}
}




void quicksort(int num[],int length,int start,int end)
{
if(start==end)//必须要有这个
return;
if(start<end)
{
int index=partition(num,length,start,end);
quicksort(num,length,start,index-1);
quicksort(num,length,index+1,end);
}
}
//快速排序 方法2


int partition1(int num[],int low,int high)
{
int key=num[low];//基准元素
while(low<high)  //从表的两端交替地向中间扫描  
{
while(low<high&&num[high]>=key)//从high 所指位置向前搜索,至多到low+1 位置。
high--;
int temp=num[low];//将比基准元素小的交换到低端 
num[low]=num[high];
num[high]=temp;
while(low<high&&num[low]<=key)//从low所指的位置向后搜索,至多到high-1位置
low++;
int temp1=num[low];//将比基准元素大的交换到后面的位置
num[low]=num[high];
num[high]=temp1;
}
return low;
}
void quicksort1(int num[],int low,int high)
{
if(low<high)
{
int index=partition1(num,low,high);//将表一分为二  
quicksort1(num,low,index-1);//递归对低子表递归排序 
quicksort1(num,index+1,high);//递归对高子表递归排序
}
}
//使用非递归的快速排序
//其实就是用栈保存每一个待排序子串的首尾元素下标,下一次while循环时取出这个范围,对这段子序列进行partition操作
/*用栈实现:
1。每次把支点的右段入栈(当然只记录该段的起始与结束标记);
2。然后继续对支点的左段重复过程1,若左段的元素小于2个,则不需要再重复1,转到3;
3。左段已排好,从栈中取出最新的右段,转到1,若栈空则结束。*/
void quicksort2(int num[],int low,int high)
{
if(low<high)
{
stack st;
int index=partition1(num,low,high);
if(low<index-1)
{
st.push(low);
st.push(index-1);
}
if(index+1<high)
{
st.push(index+1);
st.push(high);
}
while(!st.empty())
{
int p=st.pop();
int q=st.pop();
index=partition1(num,q,p);//注意这里要注意p,q的顺序,因为栈是FIFO的所以先出来的是高位,然后才是低位.所以p对应的是high,q对应的是low
if(q<index-1)
{
st.push(q);
st.push(index-1);
}
if(index+1<p)
{
st.push(index+1);
st.push(p);
}
}
}
}






//归并排序
void merge(int num[],int start,int middle,int end)
{
int *num1=new int[middle-start+2];//设置两个新数组,暂存两个分出来的子序列
int *num2=new int[end-middle+1];
for(int i=0;i<=middle-start;i++)
num1[i]=num[start+i];
num1[middle-start+1]=100000;//设置标志位,不设置这个标志位下面for循环的时候i++或者是j++会将会大于middle-start或者是end-middle-1,超过数组范围
num2[end-middle]=100000;//设置标志位,设置标志位后可以保证数组不越界
for(int j=0;j<=end-middle-1;j++)
num2[j]=num[middle+j+1];
int i=0,j=0;
for(int k=0;k<=end-start;k++)
{
if(num1[i]<=num2[j])
{
num[start+k]=num1[i];
i++;
}
else
{
num[start+k]=num2[j];
j++;
}


}
delete [] num1;
delete [] num2;
num1=NULL;
num2=NULL;
}
void mergesort(int num[],int start,int end)
{
if(start<end)
{
int middle=(start+end)/2;
mergesort(num,start,middle);
mergesort(num,middle+1,end);
merge(num,start,middle,end);
}
}
//方法2,不设置标志位,归并排序
void merge1(int num[],int start,int middle,int end)
{
int *num1=new int[middle-start+1];//设置两个新数组,暂存两个分出来的子序列,不过这种方法浪费了存储空间,可以改进为下面的方法
int *num2=new int[end-middle];
for(int i=0;i<=middle-start;i++)
num1[i]=num[start+i];
for(int j=0;j<=end-middle-1;j++)
num2[j]=num[middle+j+1];
int i=0,j=0,k=0;   //num2有end-middle个,标号从0开始,故最大j为end-middle-1。一定注意这个标号不能够设置错了
for(;k<=end-start&&i<=middle-start&&j<=end-middle-1;k++)//不设置标志位,则在循环的时候就要对i,j进行限制,防止i,j越界
{                                                       //注意这里i检测条件设置小于为middle-start+1,因为num1有middle-start+1个,但是从0开始,标号最大middle-start
if(num1[i]<=num2[j])  
{
num[start+k]=num1[i];//注意这里一定不能够设置为start++,因为这样就改变了start大小,在确定num1,num2大小的时候用到了start,造成错误
i++;                 //这里不用start的方法就是,单独在循环前令index=start
}
else
{
num[start+k]=num2[j];
j++;
}
}
while(i<=middle-start)//跳出循环肯定是因为i或者是j某一个超过了范围了
{
num[start+k]=num1[i++];
k++;
}
while(j<=middle-start-1)
{
num[start+k]=num2[j++];
k++;
}
delete [] num1;
delete [] num2;
num1=NULL;
num2=NULL;
}
void mergesort1(int num[],int start,int end)
{
if(start<end)
{
int middle=(start+end)/2;//注意这里计算出的是middle的位置,也就是中间位置的标号
mergesort1(num,start,middle);
mergesort1(num,middle+1,end);
merge1(num,start,middle,end);
}
}


//递归方法实现归并排序(方法2)
void merge3(int num[],int start,int middle,int end,int*temp)
{
int k=0,i=start,j=middle+1;
for(;i<=middle&&j<=end;)
{
if(num[i]<num[j])
temp[k++]=num[i++];
else
temp[k++]=num[j++];
}
while(i<=middle)
temp[k++]=num[i++];
while(j<=end)
temp[k++]=num[j++];
for(int index=0;index<k;index++)
num[start+index]=temp[index];//注意这里在跟新num中相应位置排序的时候不能写为index,一定要写为start+index
}
void mergesort3(int num[],int start,int end,int* temp)
{
if(start<end)
{
int middle=(start+end)/2;
mergesort3(num,start,middle,temp);
mergesort3(num,middle+1,end,temp);
merge3(num,start,middle,end,temp);
}
}






//非递归的方法实现归并排序
/**
* mergesort: 非递归实现 --迭代
* 非递归思想: 将数组中的相邻元素两两配对。用merge函数将他们排序,
* 构成n/2组长度为2的排序好的子数组段,然后再将他们排序成长度为4的子数组段,
* 如此继续下去,直至整个数组排好序。
*merge_sort(): 非递归实现-自底向上
*将原数组划分为left[min...max] 和 right[min...max]两部分
**/
void mergesort2(int arr[],int n)//参数和递归略不同,n代表数组中元素个数,即数组最大下标是n-1   
{
/* 
int step = 1; 
while(step<n) //当元素个数不是2的幂时可能会出错,未考虑第2个序列个数不足的情况  

for(int i=0;i<=n-step-1;i+=2*step) 
Merge(arr,i,i+step-1,i+2*step-1); 
step*=2; 
}*/  


int size=1,low,mid,high;  //size为步长,1,2,4,8
while(size<=n-1)  
{  
low=0;  
while(low+size<=n-1)  //先是数组元素相邻的两两相排序
{  
mid=low+size-1;  
high=mid+size;  //因此有high=low+2*size-1,因此才有最开始方法的i+step-1,i+2*step-1.
if(high>n-1)//针对二路归并的第二个序列个数不足size个的情况 ,避免了第一个方法的问题,这个问题主要存在于在最后进行归并的时候的情况,且对于最后一次的归并的情况,middle不一定是中间位置
high=n-1;         
merge(arr,low,mid,high);//调用归并子函数   
// cout<<"low:"<<low<<" mid:"<<mid<<" high:"<<high<<endl;//打印出每次归并的区间   
low=high+1;//下一次归并时第一关序列的下界   
}  
size*=2;//范围扩大一倍   
}  

//另外一种可行的方法
/*void merge_sort(int a[],int l,int r){  
int len=r-l+1;  
//枚举的是一半的长度   
for(int i=1;i<=len;i*=2){  
int left=l;  
while(left<r){  
int mid=left+i-1;  
int right=left+2*i-1;  
//中间值大于右边界,说明排好序了   
if(mid>r) break;  
//中间值没有超,右边界超了   
if(right>r) right=r;  
//mid和right相等的时候,也不需要排序   
if(right==mid) break;  
merge(a,left,mid,right);  
left=right+1;   
}  
}  
} */




//桶排序
struct bulknode
{
int data;
bulknode *next;
};
void bulksortprint(bulknode *bulk,int bulklength)
{
for(int i=0;i<bulklength;i++)
{
if(bulk[i].next==NULL)
continue;
bulknode *p=bulk[i].next;
while(p!=NULL)
{
cout<<p->data<<" ";
p=p->next;
}
}
cout<<endl;
}
void destroybulk(bulknode *bulk,int bulklength)
{
for(int i=0;i<bulklength;i++)
{
if(bulk[i].next==NULL)
continue;
while(bulk[i].next!=NULL)
{
bulknode *p=bulk[i].next;
bulk[i].next=(bulk[i].next)->next;
delete p;
}
}
}


void bulksort(int num[],int bulklength,int numlength)
{
bulknode *bulk=new bulknode[bulklength];
//清桶,桶头不放任何元素
for(int i=0;i<bulklength;i++)
{
bulk[i].data=0;//注意这里要用点操作符,点操作符仅应用与类类型的对象:左操作数必须是类类型的对象,右操作数必须是指定该类型的成员
bulk[i].next=NULL;//因为这里bulk[i]不是指针只是一个类对象,所以用点操作符
}
for(int i=0;i<numlength;i++)
{
int j=(int)(num[i]/100);
bulknode *p=new bulknode;
p->data=num[i];//箭头操作符->是点操作符和解引用操作符表达式的同义词。即(*p).data=num[i]
p->next=NULL;


bulknode *q=&bulk[j];
bulknode *r=bulk[j].next;
while(r!=NULL&&r->data<num[i])
{
q=q->next;
r=r->next;
}
q->next=p;
p->next=r;
}
bulksortprint(bulk,bulklength);
destroybulk(bulk,bulklength);
}


//基数排序
void radixsort(int num[],int length)
{
int max=num[0];
for(int i=1;i<length;i++)
{
if(num[i]>max)
max=num[i];
}
int d=1;//位数
while(max)
{
max/=10;
d++;
}
int *count=new int[10];
for(int i=0;i<10;i++)
count[i]=0;
int *temp=new int[length];
int radix=1;
for(int i=0;i<d;i++)
{
for(int j=0;j<10;j++) //每一轮进行桶排序时,要把计数器中的值清0,否则会出错,计算出来的不在是某个数的排名。
count[j]=0;
for(int j=0;j<length;j++)
{
int k=(num[j]/radix)%10;//注意这种取到各个位的数值的方法
count[k]++;
}
for(int j=1;j<10;j++)
count[j]=count[j-1]+count[j];//累加之前计算器个数,这样就可以得到排位,这个类似于计数排序
for(int j=length-1;j>=0;j--)//注意这里在必须对num从尾到头遍历,不能够从前到后遍历,即不能j=0;j<length;j++。
{
int s=(num[j]/radix)%10;//从后往前遍历是因为它是一个稳定的排序,最后出现的值,肯定在排序的时候也是排在相等的值得后面,为了保证不改变它们的出现顺序
temp[count[s]-1]=num[j];//注意这里对于cout[s]必须减去1,个数是从1开始的,而数组中保存序号是从0开始的
count[s]--;
}
for(int j=0;j<length;j++)
num[j]=temp[j];
radix=10*radix;//用于计算各个位的值得基准参数
}
delete [] count;
delete [] temp;
}


//计数排序
void countsort(int num[],int length)
{
int max=num[0];
for(int i=1;i<length;i++)
{
if(num[i]>max)
max=num[i];
}
int *count=new int[max+1];//注意是有max+1项,数组是从0到max的,故有max+1项
for(int i=0;i<=max;i++)
count[i]=0;
for(int i=0;i<length;i++)
count[num[i]]++;  //注意这里是count[num[i]]++而不是count[num[i]]=1,因为有可能有相等的元素
for(int i=1;i<=max;i++)
count[i]=count[i-1]+count[i];
int *temp=new int[length];
for(int i=length-1;i>=0;i--)//注意这里一定要是从后往前遍历,保证不改变元素出现的先后顺序
{
temp[count[num[i]]-1]=num[i];
count[num[i]]--;
}
for(int i=0;i<length;i++)
num[i]=temp[i];
delete [] temp;
delete [] count;
}


int main()
{
int length=10;
int num[]={300,421,808,675,200,912,675,999,688,570};
//insertsort(num,length);
//print(num,length);


//shellsort(num,length);
//print(num,length);


//selectsort(num,length);
//print(num,length);


//heapsort(num,length);
//print(num,length);


//bubblesort(num,length);
//print(num,length);
//bubblesort1(num,length);
//print(num,length);


//quicksort(num,length,0,length-1);
//print(num,length);
//quicksort1(num,0,length-1);
//print(num,length);
//quicksort2(num,0,length-1);
//print(num,length);


//mergesort(num,0,length-1);
//print(num,length);
mergesort1(num,0,length-1);
print(num,length);
//mergesort2(num,length);
//print(num,length);


//bulksort(num,10,length);


//radixsort(num,length);
//print(num,length);


//countsort(num,length);
//print(num,length);
return 0;
}




0 0
原创粉丝点击