浅谈排序

1、堆排序

堆排序利用了大根堆(或小根堆)堆顶记录的 关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
(1)用大根堆排序的基本思想
① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。
时间复杂度为O(log 2 n)
#include<iostream>
using namespace std;
const int N = 10;
int arr[N];
int parent(int i)
{
   return i / 2;
}//父节点
 int left(int i)
 {
   return 2 * i;
 }//孩子节点
 int right(int i)
 {
    return 2 * i + 1;
 }//右孩子节点
 void heapadjust(int i,int n)
 {
    int l,r,largest;
	l = left(i);
	r = right(i);
	if(l <= n && arr[l] > arr[i])
		largest = l;
	else largest = i;
	if(r <= n && arr[r] > arr[largest] )
		largest = r;
	if(largest != i)
	{
	   swap(arr[i],arr[largest]);
	   heapadjust(largest, n);
	   /* 
        交换后子部分可能不满足堆性质,所以递归调整。 
        堆:对任意一棵树的任意一个非叶子节点,该节点值应该大于等于(或小于)左右子节点的数据结构. 
        若满足大于等于,则为大顶堆;反之为小顶堆 
        */  

	}

 }
 /* 
初始调用buildheap将arr[1..n]变成最大堆 
因为数组最大元素在arr[1],则可以通过将arr[1]与a[n]互换达到正确位置 
现在新的根元素破坏了最大堆的性质,所以调用heapadjust调整, 
使arr[1..n-1]成为最大堆,arr[1]又是arr[1..n-1]中的最大元素, 
将arr[1]与arr[n-1]互换达到正确位置。 
反复调用heapadjust(1, i - 1),使整个数组成从小到大排序。 
*/  
 void buildheap(int n)//自底向上是因为要使最大元素升至堆顶
 {
    for(int i = n / 2;i > 0;i--)
		heapadjust(i,n);
 }
/* 
交换只是破坏了以a[1]为根的二叉树最大堆性质,它的左右子二叉树还是具备最大堆性质。 
这也是为何在build_maxheap时需要遍历n/2到1的结点才能构成最大堆,而这里只需要堆化arr[1]即可。 
*/ 
 void heap_sort(int n)
 {
    buildheap(n);
	for(int i = n;i > 1;i--)
	{
	  swap(arr[1],arr[i]);
	  heapadjust(1,i-1);
	}
 }
 int main()
 {
	 int i;
   for(i = 1;i <= 10;i++)
	   cin>>arr[i];
   heap_sort(10);
    for(i = 1;i <= 10;i++)
		cout<<arr[i]<<" ";
	cout<<endl;
	return 0;
 }


2 、归并排序
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经 排序序列之和,该空间用来存放合并后的序列
第二步:设定两个 指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
其中时间复杂度为nlogn,空间复杂度为o(n)
#include<iostream>
using namespace std;
int a[20];//定义数组a[]
int b[20];//定义辅助数组b[]
void merge(int low,int mid,int high)//合并函数
{
     int i,j,k;
	 i = low;
	 j = mid + 1;
	 k = low;
	 while(i <= mid&&j <= high)
	 {
	    if(a[i] > a[j])//找出小的数给数组b[]
			 b[k++] = a[j++];
		else b[k++] = a[i++];
	 }
	 while(i <= mid)//如果前一半没用完就继续给数组b[]
		  b[k++] = a[i++];
	 while(j <= high)//如果后一半没用完就继续给数组b[]
		 b[k++] = a[j++];
	 for(i = low;i <= high;i++)//将合并完的数组b[]复制给数组a[]
		 a[i] = b[i];

}
void merge_sort(int low,int high)//归并排序(其实就是递归的调用)
{
  int mid;
  if(low < high)
  {
     mid = (low+high) / 2;
	 merge_sort(low,mid);//左边的一半再用merge_sort
	 merge_sort(mid+1,high);//左边的一半再用merge_sort
	 merge(low,mid,high);//将排好序的前一半数和后一半数合并了
  }
}
int main()
{
	int n,i;
	cin>>n;
	for(i = 0;i < n;i++)
		cin>>a[i];
	merge_sort(0,n-1);
	for(i = 0;i < n;i++)
		cout<<a[i]<<" ";
	cout<<endl;

  return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值