数据结构六大排序有他就够了 (易理解,适合初次学习)

导航:

1,直接插入排序

2,希尔排序

3,选择排序

4,冒泡排序

5,堆排序

6,快速排序


1,直接插入排序

思路:可以理解为把待排序列依次插入到有序序列中;从后向前比较,把待插入的数同有序序列最后一个元素作比较,若比带插入的数大则向后移动,直到找到第一个小于待插入数的元素,把带插入的数放在其后即可;

动图演示:

代码示例: 

/*插入排序*/
#include<iostream>
using namespace std;
#define N 1000
int a[N]={0};


void InserSort(int *a,int n)
{
	for(int i=0;i<n-1;i++)
	{
		//记录有序序列的最后一个元素的下标
		int end = i;
		//待插入的元素
		int  t = a[end+1];
		while(end>=0)
		{
			//比插入的数大就后移
			if(t<a[end])
			{
				a[end+1]=a[end];
				end--;
			}
			//比插入数小就跳出循环
			else
			{
				break;
			}
		}
		a[end+1]=t;
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
        cin>>a[i];
	}
	//输出排序前的数组
	cout<<"排序前的数组为:"<<endl;
	for(int i=0;i<n;i++)
	{
        cout<<a[i]<<" ";
	}
	cout<<endl;
	InserSort(a,n);
	cout<<"排序后的数组为:"<<endl;
	for(int i=0;i<n;i++)
	{
        cout<<a[i]<<" ";
	}

	return 0;
}

 代码运行结果:

 

2,希尔排序

思路:希尔排序也是属于插入类排序,但其比直接插入排序效率高很多;

首先将整个待排序里分割为若干个子序列,然后分别对其进行直接插入排序,待整个序列中基本有序时再对整个待排序列进行一次插入直接插入排序;

代码展示:

/*希尔排序*/

#include<iostream>
using namespace std;
#define N 1000
int a[N]={0};

void  ShellSort(int *a,int n)
{
	int gap=n;
	while(gap>1)
	{
		//每次对gap折半操作
		gap/=2;
		//单趟排序
		for(int i=0;i<n-gap;i++)
		{
			int end=i;
			int t = a[end+gap];
			while(end>=0)
			{
				if(t<a[end])
				{
					a[end+gap]=a[end];
					end-=gap;
				}
				else
				{
					break;
				}
			}
			a[end+gap]=t;
		}
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	cout<<"排序前:"<<endl;
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<"排序后:"<<endl;
	ShellSort(a,n);
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}

	return 0;
}

排序实例:

5
9 85 6 9 2
排序前:
9 85 6 9 2 排序后:
2 6 9 9 85 

3,选择排序

 思路:从头遍历待排序(begin=0;begin++)选出最小的和序列开头元素交换(即索引为begin的位置上的元素和待排元素上最小值交换),用end=n-1 表示待排元素的最后一个元素每次end--,然后进行跌带直到begin=end 结束;

动图演示:

 

/*选择排序*/
#include<iostream>
using namespace std;

#define N 1000
int a[N]={0};
void swap(int *a,int *b)
{
	int t=*a;
	*a=*b;
	*b=t;
}
void  SelectSort(int *a,int n)
{
	//记录排序数组的第一个数和最后一个数的下标
	int begin=0,end=n-1;
	while(begin<end)
	{
		//保存最大值最小值的下标
		int maxid=begin;
		int minid=begin;
		//找出最大值和最小值的下标
		for(int i=begin;i<=end;i++)
		{
			if(a[minid]>a[i])
			{
				minid=i;
			}
			if(a[maxid]<a[i])
			{
				maxid=i;
			}
		}
		//把最小值放到开头
		swap(&a[minid],&a[begin]);
		if(maxid==begin)
		{
			maxid=minid;
		}
		//把最大值放最后
		swap(&a[maxid],&a[end]);

		begin++;
		end--;
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	cout<<"排序前为:"<<endl;
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}

	SelectSort(a,n);
	cout<<"排序后为:"<<endl;
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}
	return 0;
}

 排序案例:

10
1 3 5 12 9 49 22 13 10 44
排序前为:
1 3 5 12 9 49 22 13 10 44 排序后为:
1 3 5 9 10 12 13 22 44 49

4,冒泡排序

思路:从头遍历,相邻的两个比较左边大于右边则交换,一趟下来最大的最右边;遍历n-1次即可;

动图演示:

/*冒泡排序*/
#include<iostream>
using namespace std;

#define N 1000
int a[N]={0};

void BubbleSort(int *a,int n)
{
	for(int i=0;i<n;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			if(a[i]>a[j])
			{
				int t=a[i];
				a[i]=a[j];
				a[j]=t;
			}
		}
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	cout<<"排序前为:"<<endl;
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}

	BubbleSort(a,n);
	cout<<"排序后为:"<<endl;
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}
	return 0;
}

5,堆排序

思路:

首先要明白堆的定义:n个元素的序列{k1,k2,k3,····,kn},当且仅当满足以下关系时称之为堆。

k(i)<=k(2i)&&k(i)<=k(2i+1)     满足此关系的我们称其为小顶堆;

k(i)>=k(2i)&&k(i)>=k(2i+1)     满足此关系的我们称其为大顶堆;

堆排序思路:首先我们将待排序例按二叉树层次遍历存入,咋按照堆应瞒足的条件把其初始化为大顶堆或小顶堆,这里我们将其初始化为大顶堆,然后将堆顶取出放在序列的最后并把堆中最后一个元素移动到堆顶的位置,然后再把序列按转化成大顶堆;重复上述操作即可完成排序;

创建大顶堆动图演示:

 每次输出最大值即大顶堆的堆顶,然后取最后一个元素补上

动图演示(这里我们依次输出前三大的元素 90 36 26):

 代码补充:

/*堆排序*/
#include<iostream>
using namespace std;
#define N 1000
int a[N]={0};
void  swap(int a,int b);
void MintoBig(int *a,int i,int n);
void MintoBig(int *a,int i,int n);
void BuildHeap(int *a,int n);
//定义用于交换的函数
void  swap(int *a,int i,int j)
{
	int t=a[i];
	a[i]=a[j];
	a[j]=t;
}

//从小到大排序
void MintoBig(int *a,int i,int n)
{
	int par=i;
	int child=2*i+1;
	while(child<n)
	{
		if(a[child]<a[child+1]&&child+1<n)
		{
			child++;
		}
		//不满足上面for的条件若child+1<n则有a[child+1]<a[child]
		if(a[par]<a[child])
		{
			//交换,使其满足大顶堆的条件
			swap(a,par,child);
			par=child;//把子节点的下标赋给父节点
		}
		child=child*2+1;//换行比较下一面的

	}
}
//初始化大顶堆的函数
void BuildHeap(int *a,int n)
{
	for(int i=n/2-1;i>=0;i--)
	{
		MintoBig(a,i,n);
	}
}

void HeapSort(int *a,int n)
{
	BuildHeap(a,n);//初始化待排数组将其转化为大顶堆
	for(int i=n-1;i>0;i--)
	{
		swap(a,0,i);
		MintoBig(a,0,i);
	}

}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	cout<<"排序前:"<<endl;
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}
	HeapSort(a,n);
	cout<<"排序后:"<<endl;
	
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}

	return 0;
}

 运行结果:

 

6,快速排序

思路:快速排序是对气泡排序的一种改进,提高其效率;通过一趟排序将待排序列分割成独立两部分,其中一部分记录的关键字都比另一部分记录的关键字小,然后可再继续对对这两部分进行排序,以达到整个序列有序;

方法一:

选取每个未排序的分区第一个元素做为枢轴,定义一个元素 n = 枢轴下标 +1,遍历该未排序分区小于枢轴则呵和下标为n的交换,每次n++,最后交换枢轴和最后一个小于枢轴的元素;

 动图演示为:

 方法二:

  选取每个未排序的分区第一个元素做为枢轴,并用tem来记录枢轴的值,用begin表示该分区的第一个元素,用end表示该分区的最后一个元素,从end元素开始向前(end--)查找小于枢轴的元素,并把该元素赋给a[begin];从begin开始向后(begin++)查找大于枢轴的元素,并赋给a[end];当begin=end时该轮结束把枢轴的值赋给a[begin],此时该为排序的分区被分成两个部分,一部分都小于另一部分;

注意:每轮查找结束的标致为begin>=end;

代码展示:

#include<iostream>
using namespace std;
#define N 1000
int a[N]={0};

void QuckSort(int *a,int begin,int end)
{
	if(begin>end)
		return ;
	int i=begin;
	int j=end;
	int tem = a[begin];
	while(i<j)
	{
		while(i<j&&a[j]>=tem)
			j--;
		a[i]=a[j];
		while(i<j&&a[i]<=tem)
			i++;
		a[j]=a[i];
	}
	a[i]=tem;
	QuckSort(a,begin,i-1);
	QuckSort(a,i+1,end);
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	cout<<"排序前:"<<endl;
    for(i=0;i<n;i++)
	{
     	cout<<a[i]<<" ";
	}
	cout<<endl;
	QuckSort(a,0,n-1);
	cout<<"排序后:"<<endl;
		for(i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}


		return 0;

}

 代码运行结果:

 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值