一 .概述
八大排序算法包括
1)插入排序之直接插入排序(Straight Insertion Sort)
2)插入排序之希尔排序(Shells Sort)
3)选择排序之简单选择排序(Simple Selection Sort)
4)选择排序之堆排序(Heap Sort)
5)交换排序之冒泡排序(Bubble Sort)
6)交换排序之快速排序(Quick Sort)
7)归并排序(Merge Sort)
8 )桶排序/基数排序(Radix Sort)
二.详解
1.插入排序—直接插入排序(Straight Insertion Sort)
1)基本思想: 将一个数插入到前面已排序好的有序表中,从而得到一个新记录数增1的有序表。
要点:设立哨兵,作为临时存储和判断数组边界之用。
稳定排序:在原序列中遇到一个和插入元素相等的,那么把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,所以插入排序是稳定的。
2)代码
void print(int a[], int n ,int i){
cout<<i <<":";
for(int j= 0; j<n; j++){
cout<<a[j] <<" ";
}
cout<<endl;
}
void InsertSort(int a[], int n)
{
for(int i= 1; i<n; i++){
if(a[i] < a[i-1]){ //若第i个元素大于i-1元素,直接插入。小于的话,移动有序表后插入
int j= i-1;
int x = a[i]; //复制为哨兵,即存储待排序元素
a[i] = a[i-1]; //先后移一个元素
while(x < a[j]){ //查找在有序表的插入位置
a[j+1] = a[j];
j--; //元素后移
}
a[j+1] = x; //插入到正确位置
}
print(a,n,i); //打印每趟排序的结果
}
}
int main(){
int a[8] = {3,1,5,7,2,4,9,6};
InsertSort(a,8);
print(a,8,8);
}
对位置i的元素x进行插入分4步:保存->查找->移动->插入
Step1.先保存x.
Step2.对其左边位置[0,i-1]元素从右往左遍历,找出第一个比x小或等的元素xsmall,假设xsamll的位置为pos.
step3.将[pos+1,i-1]处的元素在插入前向后移动一位。
step4.把x插入到xsmall的后面,即把x放到pos+1的位置。
size_t findfirstminpos(vector<int>&a,size_t i)
{
size_t k=i-1;
while(a[k]>a[i])
k--;
return k;
}
void mov(vector<int> &a,size_t i,size_t j)
{
for(int k=j;k>=i;k--)
a[j+1]=a[j];
}
void InsertSort(vector<int>& a)
{
size_t asize=a.size();
for(size_t i=1;i<asize;i++){
int temp=a[i];
size_t pos=findfirstminpos(a,i);
mov(a,pos+1,i-1);
a[pos+1]=temp;
}
}
2.希尔排序
1)基本思想
又叫缩小增量排序,将待排序数列按增量分成若干个子序列,利用直接插入排序思想对子序列进行排序。
2)代码
int findfirstmin(int a[],int n,int stepp,int i)
{//在a中i以前找比i位置元素小或等的元素位置
int pos=i-stepp;
while(pos>0&&a[pos]>a[i]) pos-=stepp;
return pos;
}
void mov(int a[],int stepp,int s,int e)
{//将数组元素a[s...e]都向后移动一位,流出s的位置
while(e>=s)
{
a[e+stepp]=a[e];
e-=stepp;
}
}
void shellSort(int a[],int n,int stepp)
{
for(int i=1+stepp;i<=n;i++)
{
int k=a[i];
int pos=findfirstmin(a,n,stepp,i);
mov(a,stepp,pos+1,i-1);
a[pos]=k;
}
}
void shellInserSort(int a[],int n,int step[],int m)
{
for(int i=0;i<m;i++)
shellSort(a,n,step[i]);
}
3.简单选择排序
4.堆排序
1)基本思想
在堆中,堆的根节点的元素值一定是所有节点元素的最大值或最小值。如果将堆中根节点输出之后,将其余n-1个节点的元素值重新建立一个堆,则新堆的堆顶元素值是次大(或次小)值,将该堆顶元素输出。这样重复建堆并输出堆顶元素的过程称为堆排序。
2)
a.建堆:从最后一个非叶子节点开始调整堆,使得从该节点往下都是堆(叶子节点相当于一个堆)
b.调整堆函数:void AdjustHeap(int a,int s,int m) 第二个参数表示以s为根调整建立堆,m是要调整的a的总长度。从s开始调整说明s的下层都已经调整好了,需要把s插入到下层的某个位置。
也就是在a[s—m]中a[s]是唯一一个不符合堆规则的元素,需要调整。
3)给出一列有n个元素的数组(从位置1开始放),利用堆排序法进行排序的过程:
step1 由这n个数建立一个堆(本文用大顶堆);
step2 当最后一个元素还没有走到第一个元素的时候
step2.1 输出堆顶元素(将堆顶元素和最后一个元素交换);
step2.2 调整堆。
void adjustHeap(int a,int s,int n) //调用函数1
{
int j=2*s;
int k=a[s];
while(j<=n){
if((j+1<=n)&&a[j+1]>a[j])
j++; //j指向s子节点较大的那个
if(a[j]>a[s]) a[s]=a[j];
else break;
s=j;
j=2*s;
}
a[s]=k;
}
void createHeap(int a[],int n)//调用函数2
{
for(int s=n/2;s>=1;s--)
adjustHeap(a,s,n);
}
void heapSort(int a[],int n) //主排序
{
createHeap(a,n);
while(n>1)
{
swap(a[1],a[n]);
adjustHeap(a,1,n-1);
n--;
}
}
5.冒泡排序
6.快速排序(不稳定排序)
1)基本思想
数组data[1…n]放n个待排序元素,初始时,令left=1,right=n,令a[1]作为参考元素,然后按以下操作:
a.从right位置往前减,依次与参考元素比较,若大于等于参考则继续前移,若小于则将right处元素移到left处,令left++,进入b步骤。
b. 从left位置往后增,依次与参考元素比,若小于参考则继续后增,反之,将left处元素移到right处,令right–,进入a步骤。
2)代码
tips:一次快排使得枢轴前面的元素都小于枢轴元素,枢轴后面的元素都大于等于枢轴元素。
int partition(int a,int left,int right)//调用函数
{
int pivot=a[left];
while(left<right)
{
while(right>left&&a[right]>=pivot)
right--;
a[left]=a[right]; left++;
while(left<right&&a[left]<pivot)
left++;
a[right]=a[left];right--;
}
a[left]=pivot;
return left;
}
void quickSort(int a[],int left,int right) //主排序
{
while(left<right)
{ int pivot=partition(a,left,right); //一次快排
quickSort(a,left,pivot-1);
quickSort(a,pivot+1,right);
}
}
7.归并排序
将两个有序的s[low…mid]和s[mid+1…high]子序列归并为一个有序的序列t[low…high]:
void merge(int s[],int t[],int low ,int mid ,int high)
{//被调函数
int i=low,j=mid+1,k=low;
while(i<=mid&&j<=high)
{
if(s[i]>s[j]) t[k++]=s[i++];
else t[k++]=s[j++];
}
while(i<=mid) t[k++]=s[i++];
while(j<=high) t[k++]=s[j++];
}
void mergeSort(int s[],int t[],int low,int high)
{//主调函数,将s[low...high]归并排序后放到t[low...high]
int t2[1000];
if(low=high) t[low]=s[low];
else{
int mid=(low+high)/2;
mergeSort(s,t2,low,mid);
mergeSort(s,t2,mid+1,high);
merge(t2,t,low,mid,high);
}
}
8 .桶排序/基数排序(Radix Sort)
方法一、用二维数组
int getSortTimes(int n) //最大数的位数即为桶排序的次数
{
int count=0;
while(n)
{
n=n/10;
count++;
}
return count;
}
int getitsNum(int num,int n)//获取数num的第i位数,第1位为个位
{
for(int i=1;i<n;i++)
num=num/10;
num=num%10;
return num;
}
void distribute(int a[],int n,int buck[10][20],int pos,int index[10])
{//将数组a中的元素放入桶buck中,pos表示取哪一位的数字
for(int i=0;i<n;i++)
{
switch(getitsNum(a,pos))
{
case 0:
buck[0][index[0]++]=a[i];break;
case 1:
buck[1][index[1]++]=a[i];break;
case 2:
buck[2][index[2]++]=a[i];break;
case 3;
buck[3][index[3]++]=a[i];break;
case 4:
buck[4][index[4]++]=a[i];break;
case 5:
buck[5][index[5]++]=a[i];break;
case 6:
buck[6][index[6]++]=a[i];break;
case 7:
buck[7][index[7]++]=a[i];break;
case 8:
buck[8][index[8]++]=a[i];break;
case 9:
buck[9][index[9]++]=a[i];break;
default:
break;
}
}
}
void collect(int a[],int n,int buck[10][20],int index[])
{
int k=0;
for(int i=0;i<10;i++)
{
for(int j=0;j<index[i];j++)
{
a[k++]=buck[i][j];
buck[i][j]=0;
}
index[i]=0;
}
}
void radix_sort(int a[],int n)
{//主排序 函数
int index[10]={0};
int bucket[10][20];//一个10个桶,每个桶最多放20个数
int max=a[0];
for(int i=0;i<n;i++)
if(a[i]>max) max=a[i];
int sortTimes=getSortTimes(max);
for(int i=0;i<sortTimes;i++)
{
distribute(a,n,bucket,i+1,index);
connect(a,n,bucket,index);
}
}