排序算法复习札记
#include<iostream>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 1000;
int a[N];
int n;
void binary_sort(int a[],int n);
void bubble_sort(int a[],int n);
void bubble_sort_modify(int a[],int n);
void select_sort(int a[],int n);
void select_sort_modify(int a[],int n);
void insert_sort(int a[],int n);
void shell_sort(int a[], int n);
int partition(int a[],int p,int r);
void quick_sort(int a[],int p,int r);
int random_partition(int a[],int p,int r);
void random_quick_sort(int a[],int p,int r);
void Mergesort(int a[],int left,int right);
void Merge(int a[],int left,int mid,int right);
void Mergesort_modify(int a[],int b[],int left,int right);
void heapSort(int arr[],int n);
void heapAdjust(int arr[], int k, int n);
void count_sort_1(int *a, int n);
void CountSort(int a[],int n,int m);
void bucketSort(int arr[],int n);
int f(int x);
void count_radix(int a[], int n, int exp);
void radix_sort(int a[], int n);
int main()
{
// cin>>n;
// for(int i=0;i<n;i++)
// {
// cin>>a[i];
// }
n=10;
int a[10] = {3,24,76,345,12,87,100,30,21,456};
// int a[10] ={9,8,7,6,5,4,3,2,1,0};
// int a[10] ={5,8,7,9,2,4,3,6,0,1};
// int a[10] = {1,2,3,4,5,9,8,7,6,0};
// int a[10] ={9,78,17,86,65,54,33,42,91,20};//测试桶排序
// int a[10] ={9,20,33,86,65,54,17,42,91,78};//测试桶排序
// O(n*n)
// binary_sort(a,n);
// bubble_sort(a,n);
// bubble_sort_modify(a,n);
// select_sort(a,n);
// select_sort_modify(a,n);
// insert_sort(a,n);
// 小于O(n*n)
// shell_sort(a,n);
// O(n*logn)
// quick_sort(a,0,n-1);
// random_quick_sort(a,0,n-1);
// Mergesort(a,0,n-1);
// int b[10]={};//修改版需要的辅助数组。
// Mergesort_modify(a,b,0,n-1);
heapSort(a,n);
//O(n)
// int m=a[0];
// for(int i=1;i<n;i++) {if(a[i]>m) m=a[i];}
// CountSort(a,n,m);
// count_sort_1(a, n);
// bucketSort(a,n);
// radix_sort(a,n);
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
return 0;
}
/*********************二分排序******************/
void binary_sort(int a[],int n)
{
int l,m,r,temp;
for(int i=1;i<n;i++)//从1开始right才不会是-1。
{
l=0;
r=i-1;
temp=a[i];
while(l<=r)//注意是<= 不然的话提前退出循环了。
{
m=(l+r)/2;
if(temp<a[m])
{
r=m-1;
}
else
{
l=m+1;
}
}
for(int j=i-1;j>=l;j--)
{
a[j+1]=a[j];
}
a[l]=temp;
}
}
/***********************************************/
/*********************冒泡排序******************/
void bubble_sort(int a[],int n)//一种i、j的写法
{
int temp;
for(int i=1;i<n;i++)
{
for(int j=0;j<n-i;j++)//j<n-i一趟冒泡完成大的数沉底
{
if(a[j+1]<a[j])
{
temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
}
}
}
/***********************************************/
/*********************冒泡排序改进版*********************/
void bubble_sort_modify(int a[],int n)//另外一种i、j的写法
{
int temp;
int flag=1;
for(int i=n;i>1&&flag==1;i--)
{
flag=0;
for(int j=0;j<i-1;j++)//j<i-1(j+1 不能越界)
{
if(a[j+1]<a[j])
{
flag=1;
temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
}
}
}
/***********************************************/
/*********************选择排序**********************/
void select_sort(int a[],int n)// 改进版本,原本小于就直接交换
{
int t;
for(int i=0;i<n-1;i++)
{
int temp=a[i];
t=i;
for(int j=i+1;j<n;j++)
{
if(a[j]<temp)
{
temp=a[j];
t=j;
}
}
a[t]=a[i];
a[i]=temp;
}
}
/*********************************************/
// void select_sort_modify(int a[],int n)//这个算法有点问题哈!稳定性不好m=n-1时候有可能会出错
// { //学校里搞到的
// int m=0;
// int temp;
// for (int size = n; size > 1; size--)
// {
// int pos = 0;
// for (int i = 1; i < size; i++)//确定a[0:n-1]中最大元素的下标
// {
// if (a[pos] < a[i])
// {
// pos = i;
// m++;
// }
// }
// temp=a[pos];
// a[pos]=a[size-1];
// a[size-1]=temp;
// if(m==n-1)
// break;
// }
// }
void select_sort_modify(int a[],int n)//双向选择版本。
{
for(int left=0,right=n-1; left < right; left++, right--)
{
for (int i = left; i < right; i++)
{
int temp = a[i];
if (a[left] > a[i])
{
a[i] = a[left];
a[left] = temp;
}
if (a[right] < a[i])
{
a[i] = a[right];
a[right] = temp;
}
}
}
}
/*************************************************/
/**********************插入排序*******************/
void insert_sort(int a[],int n)
{
int key;
for(int j=1,i;j<n;j++)
{
key = a[j];
i=j-1;
while ((i>=0)&&(a[i]>key)) //先进行移位,后面才能插入
{
a[i+1]=a[i];
i--;
}
a[i+1]=key;
}
}
/***************************************************/
/******************希尔排序*************************/
//核心思想还是使用插入排序算法
//通过分组,让数据在小规模内有序,减小递归增量使得整体有序
void shell_sort(int a[], int n)
{
int i, j, k, temp;
int gap = n;
while(gap!=1)
{
//gap的选择可以有多中方案,如gap = gap/2,这里使用的是业界统一实验平均情况最好的,收敛为1
gap = gap / 3 + 1;
for (i = gap; i < n; i += gap) //分成len/gap组
{
//每组使用插入排序
k = i;
temp = a[k];
for (j = i - gap; (j >= 0) && (a[j] > temp); j -= gap)
{
a[j + gap] = a[j];
k = j;
}
a[k] = temp;
}
}
}
/****************************************************/
/*****************快速排序******************/
void quick_sort(int a[],int p,int r)
{
if(p<r)
{
int q=partition(a,p,r);
quick_sort(a,p,q-1);
quick_sort(a,q+1,r);
}
}
/*****************好理解版本*********************/
// int partition(int a[],int p,int r)
// {
// int x=a[r]; //末尾元素作为主元
// int i=p-1;
// int temp;
// for(int j=p;j<=r-1;j++)//若? ? > ?,则?右移
// {
// if(a[j]<=x)//若?[j]≤ ?,则交换?[?]和?[? + ?],?, ?右移
// {
// temp=a[i+1];
// a[i+1]=a[j];
// a[j]=temp;
// i=i+1;
// }
// }
// temp=a[i+1];//i+1左边的元素都是比主元小
// a[i+1]=a[r];
// a[r]=temp;
// int q=i+1;//可以不用,直接返回i+1
// return q;
// }
//***************双向比较******************/
int partition(int a[],int p,int r)
{
int i=p,j=r+1;
int x=a[p];
int temp;
while(true)
{
while(a[++i]<x);
while(a[--j]>x);
if(i>=j) break;
temp=a[j];
a[j]=a[i];
a[i]=temp;
}
a[p]=a[j];
a[j]=x;
return j;
}
void random_quick_sort(int a[],int p,int r)
{
if(p<r)
{
int q=random_partition(a,p,r);
random_quick_sort(a,p,q-1);
random_quick_sort(a,q+1,r);
}
}
int random_partition(int a[],int p,int r)
{
srand((unsigned)time(NULL)); //设置种子,避免产生伪随机数
int s =rand()%(r-p+1)+p; //产生[p:r]的随机数
int temp=a[s];
a[s]=a[p];
a[p]=temp;
return partition(a,p,r);
}
/****************************************************/
/***********************归并排序**********************/
void Mergesort(int a[],int left,int right)
{
if(left>=right)
{
return ; //递归终止:仅有一个元素
}
int mid=(left+right)>>1;
Mergesort(a,left,mid);
Mergesort(a,mid+1,right);
Merge(a,left,mid,right);
}
void Merge(int a[],int left,int mid,int right)
{
ll b[right+1]; //辅助的数组
for(int i=left;i<=right;i++)
{
b[i]=a[i];
}
int i=left;
int j=mid+1;
int k=0;
while((i<=mid)&&(j<=right))//遍历子数组,进行合并
{
if(b[i]<=b[j])
{
a[left+k]=b[i];
++k;
++i;
}
else
{
a[left+k]=b[j];
++k;
++j;
}
}
if(i<=mid) //添加剩余元素保证有序
{
for(int t=left+k;t<=right;++t)//mid+1到right已经遍历完
{
a[t]=b[i];
++i;
}
}
else
{
for(int t=left+k;t<=right;++t)//left到mid遍历完
{
a[t]=b[j];
++j;
}
}
}
/**********************************/
void Mergesort_modify(int a[],int b[],int left,int right)
{
if(left>=right)//R.Sedgewickg改进算法
{
return ; //递归终止:仅有一个元素
}
int mid=(left+right)>>1;
Mergesort_modify(a,b,left,mid);
Mergesort_modify(a,b,mid+1,right);
int i,j,k;
for(i=mid;i>=left;i--) {b[i]=a[i];}
//本算法巧妙之处:将第二个子数组中的元素顺序颠倒过来
for(j=1;j<=right-mid;j++) {b[right-j+1]=a[j+mid];}
for(i=left,j=right,k=left;k<=right;k++)
{
if(b[i]<b[j])//i和j向mid靠拢,无论哪个遍历过中点还是要比较
a[k]=b[i++];
else
a[k]=b[j--];
}
}
/************************************************/
void heapSort(int arr[],int n)
{
for(int i = n/2;i>=0;i--)//建堆
{
heapAdjust(arr,i,n-1);
}
for(int i=n-1;i>=1;i--)
{
int temp=arr[0];
arr[0]=arr[i];
arr[i]=temp;
heapAdjust(arr,0,i-1);
}
}
/****************************小顶堆*********************/
// void heapAdjust(int arr[], int k, int n)//小顶堆输出逆序。
// {
// int temp=arr[k];
// int i,j;
// i=k;
// j=2*i;
// while (j<n)
// {
// if (j<n && arr[j] > arr[j + 1])//子节点中找较小的
// {
// j++;
// }
// if (temp > arr[j])
// {
// arr[i]=arr[j];
// i = j;
// j = j*2;
// }
// else break;
// }
// arr[i]=temp;
// }
/****************************大顶堆********************/
void heapAdjust(int arr[], int k, int n)//大顶堆输出正序。
{
int temp=arr[k];
int i,j;
i=k;
j=2*i;
while (j<n)
{
if (j<n && arr[j] < arr[j + 1])//子节点中找较大的
{
j++;
}
if (temp < arr[j])
{
arr[i]=arr[j];
i = j;
j = j*2;
}
else break;
}
arr[i]=temp;
}
/***********************计数排序****************/
void count_sort_1(int *a, int n)//计数排序
{
int max = a[0];
int min = a[0];
for (int i = 0; i < n; i++)
{
if (a[i]>max)
{
max = a[i];
}
if (a[i] < min)
{
min = a[i];
}
}
int range = max - min + 1;//获取基数
int* countArray = new int[range+1];//实际操作中直接设置大小
memset(countArray, 0, sizeof(ll)*range);//把新开辟的数组初始化为0
for (int i = 0; i < n; i++)//遍历原数组统计每个数字出现的次数
{
countArray[a[i] - min]++;
}
int index = 0;
for (int i = 0; i < range; i++)//遍历范围,对原数组进行排序
{
while (countArray[i]--)
{
a[index] = i + min;
index++;
}
}
delete [] countArray;
}
//计数排序,将数字映射成数组下标,然后遍历一遍就可知道其所在位置。
void CountSort(int a[],int n,int m)
{
int b[n];
int c[m+1]={};
for(int i=0;i<n;i++) c[a[i]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--)
{
b[c[a[i]]-1]=a[i];
c[a[i]]--;
}
for(int i=0;i<n;i++)
{
a[i]=b[i];
}
}
/******************************/
/***************************桶排序*****************/
//桶排序,计数排序的升级版,实际上计数排序就是桶的个数十分多的时候的例子。
//映射函数,决定这个数应该放到哪一个桶里面。
//然后对每个桶单独排序,保证下一个桶的最大值必定大于上一个桶的最小值。
int f(int x)
{
return x/10;
}
void bucketSort(int arr[],int n)
{
int bucketNums = 10;//桶的个数
vector<int>ve[10];//记录每一个桶里面有的数
for(int i=0;i<n;i++)
{
int temp = f(arr[i]);
ve[temp].push_back(arr[i]);
}
//单独对每个桶排序
for(int i=0;i<bucketNums;i++)
{
if(ve[i].size()==0) continue;
sort(ve[i].begin(),ve[i].end());
}
int k = 0;
for(int i=0;i<bucketNums;i++)
{
int size = ve[i].size();
for(int j = 0;j<size;j++)
{
arr[k++] = ve[i][j];
}
}
}
/****************************************************/
//基数排序,对一列数字,先根据个位进行排序,然后根据十位进行排序。。依次
int get_max(int a[], int n)
{
int i, max;
max = a[0];
for (i = 1; i < n; i++)
if (a[i] > max)
max = a[i];
return max;
}
void count_radix(int a[], int n, int exp)
{
int output[n]; // 存储"被排序数据"的临时数组
int i, buckets[10] = {0};
// 将数据出现的次数存储在buckets[]中
for (i = 0; i < n; i++)
buckets[ (a[i]/exp)%10 ]++;
// 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。
for (i = 1; i < 10; i++)
buckets[i] += buckets[i - 1];
// 将数据存储到临时数组output[]中
for (i = n - 1; i >= 0; i--)
{
output[buckets[ (a[i]/exp)%10 ] - 1] = a[i];
buckets[ (a[i]/exp)%10 ]--;
}
// 将排序好的数据赋值给a[]
for (i = 0; i < n; i++)
{
a[i] = output[i];
}
}
void radix_sort(int a[], int n)
{
int exp; // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...
int max = a[0];
for (int i = 1; i < n; i++)
{
if (a[i] > max)
max = a[i];
}
// 从个位开始,对数组a按"指数"进行排序
for (exp = 1; max/exp > 0; exp *= 10)
count_radix(a, n, exp);
}
部分代码参考他人,忘记出处了,在此感谢,如有错误,谢谢您的提醒。