排序算法复习札记

排序算法复习札记

#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);
}

 部分代码参考他人,忘记出处了,在此感谢,如有错误,谢谢您的提醒。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值