#include<iostream>
using namespace std;
void out(int *arr,int len) {
for(int i=0; i<len; i++) {
printf("%d ",arr[i]);
}
printf("\n");
}
//简单排序:选择、冒泡、直接插入
/*
选择排序:从无序区选择一个最值放进有序区。
*/
void choice(int *arr,int len) {
for(int i=0; i<len-1; i++) {
int min=arr[i];
int k=i;
for(int j=i+1; j<len; j++) {
if(arr[j]<min) {
min=arr[j];
k=j;
}
}
if(k!=i) {
int temp=arr[k];
arr[k]=arr[i];
arr[i]=temp;
}
}
}
/*
冒泡排序:动态排序,每一趟经过比较得到一个最值
*/
void bubble(int *arr,int len) {
for(int i=0; i<len-1; i++) {
for(int j=0; j<len-i-1; j++) {
if(arr[j]>arr[j+1]) {
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
//直接插入排序:从原序列中逐一拿来建序;从端部一直比较,得到插入位置
void direct_insert(int *arr,int len) {
if(len<1)return;
for(int i=1; i<len; i++) {
if(arr[i]<arr[i-1]) {
int j=i-1;
while(j>=0) {
if(arr[i]>=arr[j]) {
break;
}
j--;
}
int temp=arr[i];
for(int k=i-1; k>=j+1; k--) {
arr[k+1]=arr[k];
}
arr[j+1]=temp;
}
}
}
/*
希尔排序(直接插入排序的改进):间隔gap分组,直到gap=1;对每个分组进行直接插入排序;
*/
void shell(int *arr,int len,int gap,int dgap) {
if(len<1||gap>len||gap<1||dgap>gap) {
printf("参数错误!\n");
return;//条件
}
while(gap>=1) { //gap逐渐减小到1,分为gap组
for(int i=0; i<gap; i++) {
//对每一组进行直接插入排序
for(int j=i; j<len; j=j+gap) {
int t=arr[j];
for(int k=j-gap; k>=0; k=k-gap) {
if(t>=arr[k])break;
int temp=arr[k+gap];
arr[k+gap]=arr[k];
arr[k]=temp;
}
}
}
gap=gap/dgap;
}
}
/*
快排(冒泡排序的改进):递归写法。
一趟排序:选择分组的第一个元素作为标杆key,从后往前与 key比较和从前往后与key比较,将
分成左边小于key的部分和key右边大于 key的部分。
算法:注意临界数据
*/
void swap(int *arr,int v1,int v2) {
int temp=arr[v1];
arr[v1]=arr[v2];
arr[v2]=temp;
}
void quick(int *arr,int l,int r) {
if(l>=r)return;
int key=arr[l];
int i=l;
int j=r;
while(i!=j) {
while(arr[j]>=key&&j>i) {
j--;
}
swap(arr,i,j);
while(arr[i]<=key&&j>i) {
i++;
}
swap(arr,i,j);
}
quick(arr,l,i-1);
quick(arr,i+1,r);
}
//快排的递推写法
void quick2(int *arr,int l,int r) {
}
/*
堆排序算法(选择排序的改进):主要实现在结点下滑算法 。
1. 初始堆(这里建成最大堆)
将数组元素逻辑上构造成完全二叉树,在从非叶结点到根结点依次执行下滑。
2. 调整堆
将根结点和最后一个无序区叶结点交换,然后将交换后的叶结点归为有序区,直到有序区的个数为n-1;
*/
void glidedown(int *arr,int len,int index) {
if(index>=len)return;
if(index*2+1<len) { //有左海子
if(index*2+2<len) { //并且有右孩子
if(arr[index*2+1]<arr[index*2+2]) { //下滑到最大的那个孩子
if(arr[index]<arr[index*2+2]) {
swap(arr,index,index*2+2);
glidedown(arr,len,index*2+2);
}
} else {
if(arr[index]<arr[index*2+1]) {
swap(arr,index,index*2+1);
glidedown(arr,len,index*2+1);
}
}
} else { //有左海子,没有右孩子
if(arr[index]<arr[index*2+1]) {
swap(arr,index,index*2+1);
glidedown(arr,len,index*2+1);
}
}
}
}
void heap(int *arr,int len) {
//最后一个非叶结点下标
int ny_index=(len-1-1)/2;
//1. 造初始堆
for(int i=ny_index; i>=0; i--) {
glidedown(arr,len,i);
}
printf("初始堆:\n");
out(arr,len);
//2. 调整堆(从最后一个无序区结点开始调整,调整n-1次)
int count=0;
for(int j=len-1; j>=1; j--) {
swap(arr,0,j);
count++;
int ny_index2=(j-1)/2;
for(int k=ny_index2; k>=0; k--) {
glidedown(arr,len-count,k);
}
}
}
/*
归并排序:采用分治法。
将两个有序的数列合并为一个有序数列
合并算法:1. 有一个存放有序序列的空间
2. 两个指针分别指向两个有序数列起始位置
3. 将指针所比较的最值放进有序空间,指针移动
上面的2,3再循环完成两序列的合并
*/
void merge_two(int *arr,int *temp,int start,int mid,int end){
int i=start;
int j=mid+1;
int k=0;
while(i<=mid&&j<=end){
if(arr[i]<arr[j]){
temp[k++]=arr[i++];
}else{
temp[k++]=arr[j++];
}
}
while(i<=mid){
temp[k++]=arr[i++];
}
while(j<=end){
temp[k++]=arr[j++];
}
//注意这里
for(int h=0;h<k;h++){
arr[start++]=temp[h];
}
}
void merge(int *arr,int *temp,int start,int end){
if(start>=end)return;
int mid=(start+end)/2;
merge(arr,temp,start,mid);
merge(arr,temp,mid+1,end);
merge_two(arr,temp,start,mid,end);
}
/*
排序算法选择:1.数据的量n的大小,2.数据的分布 3. 稳定性(是否改变原相同数值的相当位置)
1. 若n较小,可采用直接插入排序法或选择排序法
2. 若n较小且数据分布有序,可以采用直接插入排序法或冒泡排序法
3. 若n大,应采用快排,堆排序,或归并排序
*/
int main() {
int a[]= {10,4,5,8,3,2,1,7,6,9};
//choice(a,10);
//bubble(a,10);
//direct_insert(a,10);
//shell(a,10,10,2);
//quick(a,0,9);
//heap(a,10);
printf("输出结果:\n");
int temp[10];
merge(a,temp,0,9);
out(a,10);
return 0;
}
排序算法
最新推荐文章于 2024-08-19 21:46:47 发布