常见排序算法整理

最近花了点时间把几个常用的排序算法在此做个总结,下面是代码。

1、直接插入排序

输入数组为{16,14,10,8,7,9,3,2,4,1},按照从小到大排序。

右边的无序数不断地往左边的有序数部分进行比较然后插入

16 14 10 8 7 9 3 2 4 1

14 16 10 8 7 9 3 2 4 1

10 14 16 8 7 9 3 2 4 1

8 10 14 16 7 9 3 2 4 1

7 8 10 14 16 9 3 2 4 1

7 8 9 10 14 16 3 2 4 1

3 7 8 9 10 14 16 2 4 1

2 3 7 8 9 10 14 16 4 1

2 3 4 7 8 9 10 14 16 1

1 2 3 4 7 8 9 10 14 16


// 直接插入排序
/*
思想:每次选择一个元素K=data[i]插入到之前已排好序的部分data[0…i-1]中,插入过程中K依次
由后向前与data[0…i-1]中的元素进行比较。若发现发现data[x]>=K,则将K插入到A[x]的后面,插入前需要移动元素。
*/
void InsertSort(vector<int> & data) {
	int n = data.size();//数组长度
	int i,j;
	int temp;
	for(i=0;i<n;i++)
	{
		temp = data[i];
		j = i-1;//从右向左在有序区data[0...i-1]找data[i]的插入位置
		while(j>=0 && temp<data[j])
		{
			data[j+1] = data[j];//将值大于data[i]向右移动
			j--;
		}
		data[j+1] = temp;//在j+1处插入data[i]
	}
}

2、冒泡排序

输入数组为{16,14,10,8,7,9,3,2,4,1},按照从小到大排序。

右边无序数中的最小数通过不断交换移到左边

1 16 14 10 8 7 9 3 2 4

1 2 16 14 10 8 7 9 3 4

1 2 3 16 14 10 8 7 9 4

1 2 3 4 16 14 10 8 7 9

1 2 3 4 7 16 14 10 8 9

1 2 3 4 7 8 16 14 10 9

1 2 3 4 7 8 9 16 14 10

1 2 3 4 7 8 9 10 16 14

1 2 3 4 7 8 9 10 14 16


//冒泡排序
//从最右侧的元素开始搜索并交换,找出最小的数移到无序的最左位置
void BubbleSort(vector<int> & data) {
	int n = data.size();//数组长度
	int i,j;
	int temp;
	for(i=0;i<n-1;i++)//n趟
	{
		for(j=n-1;j>i;j--)//找出本趟次最小的数,移到无序的最左处
		{
			if(data[j]<data[j-1])//后面的数比前面的小就交换
			{
				temp = data[j];
				data[j] = data[j-1];
				data[j-1] = temp;
			}
		}
	}

}


3、快速排序



//快速排序
//最核心的思想是将小的部分放在左边,大的部分放到右边,实现分割。
//每次都需要和中轴元素交换,因此原来的顺序就可能被打乱,所以不稳定
void QuickSort(int data[],int s,int t) {
	int i=s,j=t;
	int temp;
	if(s<t)
	{
		temp = data[s];//取data[s...t]最左侧的元素作为中轴元素
		while(i!=j){
			while(j>i && data[j]>temp) j--;//从右往左找到第一个比temp值要小的数data[j]
			if(i<j){data[i]=data[j];i++;}//data[j]移到左侧,i++

			while(i<j && data[i]<temp) i++;//从左往右找到第一个比temp值要大的数
			if(i<j){data[j]=data[i];j--;}//data[i]移到右侧,j--
		}
		data[i] = temp;
		QuickSort(data,s,i-1);//对左段继续分割
		QuickSort(data,i+1,t);//对右段继续分割
	}
}


4、直接选择排序

输入数组为{16,14,10,8,7,9,3,2,4,1},按照从小到大排序。

右边无序数的最小数与无序数中的第一个数进行交换

1 14 10 8 7 9 3 2 4 16

1 2 10 8 7 9 3 14 4 16

1 2 3 8 7 9 10 14 4 16

1 2 3 4 7 9 10 14 8 16

1 2 3 4 7 9 10 14 8 16

1 2 3 4 7 8 10 14 9 16

1 2 3 4 7 8 9 14 10 16

1 2 3 4 7 8 9 10 14 16

1 2 3 4 7 8 9 10 14 16


// 直接选择排序
void SelectSort(vector<int> & data) {
	int n = data.size();//数组长度
	int i,j,k;
	int temp;
	for(i=0;i<n-1;i++)
	{
		k = i;
		for(j=i+1;j<n;j++)//在右边无序数中找最小数
		{
			if(data[j]<data[k])//记录最小数的位置
				k=j;
		}
		if(k!=i)//最小数data[k]跟无序数中首个数data[i]交换
		{
			temp = data[i];
			data[i] = data[k];
			data[k] = temp;
		}
	}
}


5、堆排序

输入数组为{16,14,10,8,7,9,3,2,4,1},按照从小到大排序。

初始化为最大堆,取出堆顶最大元素跟堆的最后一个元素交换,再重新调整堆

16 14 10 8 7 9 3 2 4 1 初始化为最大堆

14 8 10 4 7 9 3 2 1 16

10 8 9 4 7 1 3 2 14 16

9 8 3 4 7 1 2 10 14 16

8 7 3 4 2 1 9 10 14 16

7 4 3 1 2 8 9 10 14 16

4 2 3 1 7 8 9 10 14 16

3 2 1 4 7 8 9 10 14 16

2 1 3 4 7 8 9 10 14 16

1 2 3 4 7 8 9 10 14 16


//调整堆,交换较大数  
void adjustHeap(int A[],int s,int e)  
{  
    int i = s,j=2*i,tmp;//数组第j个元素是第i个的左子树  
    tmp = A[i-1];  
    while(j<=e)  
    {  
        if(j<e && A[j-1]<A[j])//取左、右子树中的较大者  
            j++;  
        if(A[j-1]>tmp)  
        {  
            A[i-1]=A[j-1];//交换较大数  
            i=j;  
            j=2*i;//更新位置,进行下一轮调整  
        }  
        else  
        {  
            break;  
        }  
    }  
    A[i-1] = tmp;//最终位置  
}  
//堆排序  
void heapsort(int data[],int n)  
{  
    int i,tmp;  
    //初始化为最大堆  
    for(i=n/2;i>=1;i--)  
    {  
        adjustHeap(data,i,n);  
    }
    for(i=n;i>=2;i--)//i==1只有一个元素就不用调整了  
    {  
        tmp = data[0];//取出堆顶最大元素跟堆的最后一个元素交换  
        data[0] = data[i-1];  
        data[i-1] = tmp;  
        adjustHeap(data,1,i-1);//此时堆大小-1 
    }  
} 


6、归并排序

归并排序其实要做两件事:

(1)“分解”——将序列每次折半划分

(2)“合并”——将划分后的序列段两两合并后排序


//合并两个有序的
void Merge(int r[],int r1[],int s,int m,int t)
{
	int i=s;
	int j=m+1;
	int k=s;
	//有序排列到r1中
	while(i<=m && j<=t){
		if(r[i]<=r[j])
			r1[k++]=r[i++];
		else
			r1[k++]=r[j++];
	}
	if(i<=m)//[i,m]还有剩
	{
		while(i<=m)
			r1[k++]=r[i++];
	}
	else//[m+1,t]还有剩
	{
		while(j<=t)
			r1[k++]=r[j++];
	}
	//将r1赋给r
	for(int n=s;n<=t;n++)
		r[n]=r1[n];
}

//归并排序是空间换时间
void MergeSort(int r[],int r1[],int s,int t)
{
	if(s<t)
	{
		int m=(s+t)/2;//求取中间元素坐标,将数组分为两部分
		MergeSort(r,r1,s,m);//[s,m]
		MergeSort(r,r1,m+1,t);//[m+1,t]
		Merge(r,r1,s,m,t);
	}
}



完整可运行代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <algorithm>
#include <math.h>

using namespace std;

// 直接插入排序
/*
思想:每次选择一个元素K=data[i]插入到之前已排好序的部分data[0…i-1]中,插入过程中K依次
由后向前与data[0…i-1]中的元素进行比较。若发现发现data[x]>=K,则将K插入到A[x]的后面,插入前需要移动元素。
*/
void InsertSort(vector<int> & data) {
	int n = data.size();//数组长度
	int i,j;
	int temp;
	for(i=0;i<n;i++)
	{
		temp = data[i];
		j = i-1;//从右向左在有序区data[0...i-1]找data[i]的插入位置
		while(j>=0 && temp<data[j])
		{
			data[j+1] = data[j];//将值大于data[i]向右移动
			j--;
		}
		data[j+1] = temp;//在j+1处插入data[i]
	}
}

//冒泡排序
//从最右侧的元素开始搜索并交换,找出最小的数移到无序的最左位置
void BubbleSort(vector<int> & data) {
	int n = data.size();//数组长度
	int i,j;
	int temp;
	for(i=0;i<n-1;i++)//n趟
	{
		for(j=n-1;j>i;j--)//找出本趟次最小的数,移到无序的最左处
		{
			if(data[j]<data[j-1])//后面的数比前面的小就交换
			{
				temp = data[j];
				data[j] = data[j-1];
				data[j-1] = temp;
			}
		}
	}
}


//快速排序
//最核心的思想是将小的部分放在左边,大的部分放到右边,实现分割。
//每次都需要和中轴元素交换,因此原来的顺序就可能被打乱,所以不稳定
void QuickSort(int data[],int s,int t) {
	int i=s,j=t;
	int temp;
	if(s<t)
	{
		temp = data[s];//取data[s...t]最左侧的元素作为中轴元素
		while(i!=j){
			while(j>i && data[j]>temp) j--;//从右往左找到第一个比temp值要小的数data[j]
			if(i<j){data[i]=data[j];i++;}//data[j]移到左侧,i++

			while(i<j && data[i]<temp) i++;//从左往右找到第一个比temp值要大的数
			if(i<j){data[j]=data[i];j--;}//data[i]移到右侧,j--
		}
		data[i] = temp;
		QuickSort(data,s,i-1);//对左段继续分割
		QuickSort(data,i+1,t);//对右段继续分割
	}
}

// 直接选择排序
void SelectSort(vector<int> & data) {
	int n = data.size();//数组长度
	int i,j,k;
	int temp;
	for(i=0;i<n-1;i++)
	{
		k = i;
		for(j=i+1;j<n;j++)//在右边无序数中找最小数
		{
			if(data[j]<data[k])//记录最小数的位置
				k=j;
		}
		if(k!=i)//最小数data[k]跟无序数中首个数data[i]交换
		{
			temp = data[i];
			data[i] = data[k];
			data[k] = temp;
		}
	}
}

//调整堆,交换较大数  
void adjustHeap(int A[],int s,int e)  
{  
    int i = s,j=2*i,tmp;//[j]是[i]的左子树  
    tmp = A[i-1];  
    while(j<=e)  
    {  
        if(j<e && A[j-1]<A[j])//取左、右子树中的较大者  
            j++;  
        if(A[j-1]>tmp)  
        {  
            A[i-1]=A[j-1];//交换较大数  
            i=j;  
            j=2*i;//更新位置,进行下一轮调整  
        }  
        else  
        {  
            break;  
        }  
    }  
    A[i-1] = tmp;//最终位置  
}  
//堆排序  
void heapsort(int data[],int n)  
{  
    int i,tmp;  
    //初始化为最大堆  
    for(i=n/2;i>=1;i--)  
    {  
        adjustHeap(data,i,n);  
    }
    for(i=n;i>=2;i--)//i==1只有一个元素就不用调整了  
    {  
        tmp = data[0];//取出堆顶最大元素跟堆的最后一个元素交换  
        data[0] = data[i-1];  
        data[i-1] = tmp;  
        adjustHeap(data,1,i-1);//此时堆大小-1 
    }  
} 

//合并两个有序的
void Merge(int r[],int r1[],int s,int m,int t)
{
	int i=s;
	int j=m+1;
	int k=s;
	//有序排列到r1中
	while(i<=m && j<=t){
		if(r[i]<=r[j])
			r1[k++]=r[i++];
		else
			r1[k++]=r[j++];
	}
	if(i<=m)//[i,m]还有剩
	{
		while(i<=m)
			r1[k++]=r[i++];
	}
	else//[m+1,t]还有剩
	{
		while(j<=t)
			r1[k++]=r[j++];
	}
	//将r1赋给r
	for(int n=s;n<=t;n++)
		r[n]=r1[n];
}


//归并排序是空间换时间
void MergeSort(int r[],int r1[],int s,int t)
{
	if(s<t)
	{
		int m=(s+t)/2;//求取中间元素坐标,将数组分为两部分
		MergeSort(r,r1,s,m);//[s,m]
		MergeSort(r,r1,m+1,t);//[m+1,t]
		Merge(r,r1,s,m,t);
	}
}
int main()
{
	//数组初始化vector
	int iarray[]={16,14,10,8,7,9,3,2,4,1};

	//count: iarray数组个数
	size_t count=sizeof(iarray)/sizeof(int);
	//int数组初始化 ivec3
	vector<int> a(iarray,iarray+count);

#if 0
	BubbleSort(a);

	for(int i=0;i<count;i++)
	{
		printf("%d\n",a[i]);
	}
#endif

#if 1
	//QuickSort(iarray,0,count-1);
	heapsort(iarray,count);

	for(int i=0;i<count;i++)
	{
		printf("%d\n",iarray[i]);
	}
#endif

	system("pause");
	return 0;
}



参考资料:

[1]【常见排序算法小结】http://blog.csdn.net/whuslei/article/details/6442755

[2]【经典排序算法】http://www.cnblogs.com/kkun/archive/2011/11/23/2260312.html

[3]【八种必须掌握的排序算法】https://zhuanlan.zhihu.com/p/26065419?utm_source=qq&utm_medium=social

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值