各种排序

<pre name="code" class="cpp">#include <iostream>
using namespace std;

class Solution{
public:
	//冒泡排序
	//比较相邻的两个元素,如果前面大于后面,则交换,每一轮过后,最大的那个数就放到了最后一个
	//优化1:如果没有发生变化,那么证明已经是排好序了,则不需要再继续下一轮
	//优化2:如果有100个数的数组,仅前面10个无序,后面90个都已排好序且都大于前面10个数字。记录第一次交换的位置即可。
	void bubbleSort1(int A[],int n)
	{
		for(int i=0;i<n;i++)
			for(int j = 1;j <n-i;j++)
				if (A[j-1] > A[j])
					swap(A[j-1],A[j]);
	}

	void bubbleSort2(int A[],int n)
	{
		bool flag = true;
		int k = n;

		while(flag)
		{
			flag = false;
			for(int i = 1;i < k;i++)
			{
				if(A[i-1] > A[i])
				{
					swap(A[i-1],A[i]);
					flag = true;
				}
			}
			k--;
		}
	}

	void bubbleSort3(int A[],int n)
	{
		int pos = n;
		int k = n;
		bool flag = true;
		while(flag)
		{
			flag =false;
			k = pos;
			for(int i =1;i<k;i++)
			{
				if(A[i-1] > A[i])
				{
					swap(A[i-1],A[i]);
					pos = i;
					flag = true;
				}
			}
		}
	}

	//直接插入排序
	//将A[i],插入到[0,i-1]的有序空间,且保持有序。
	//将A[i]于A[i-1]比较,如果A[i-1]小于A[i],啥也不做;否则,交换A[i-1]和A[i],j--,一直到A[i-1]小于A[i].
	void insertSort(int A[],int n)
	{
		for(int i=0;i<n;i++)
			for(int j=i-1;j>=0&&A[j]>A[j+1];j--)				
				swap(A[j],A[j+1]);
	}

	//希尔排序
	//gap=n/2,每相隔gap个元素进行插入排序。gap=gap/2,再插入排序,直到gap=0;
	//比如10个元素,gap为5.就分成了5组数据,每组元素为2.对每组进行插入排序。
	//思路1,最紧扣定义的写法。
	void shellSort1(int A[],int n)
	{
		for(int gap=n/2;gap>0;gap=gap/2)//步长
		{
			for(int i=0;i<gap;i++)//一共gap组数据
			{
				for(int j=i+gap;j<n;j+=gap)//对每组数据进行排序
				{
					if(A[j] < A[j-gap])
					{
						int k;
						int tmp = A[j];//记录A[j]的值
						for(k = j-gap;k>=0 && A[k] > tmp;k-=gap)
						{
							//比tmp大的数,则往后移位
							A[k+gap] = A[k];
						}

						//此时A[k]是比tmp小的位置,则k+gap则是应该插入的位置
						A[k+gap] = tmp;
					}
				}
			}
		}
	}

	//上面的思路代码量比较大。思路2.从gap元素开始,每个元素与组内的元素进行插入排序。
	void shellSort2(int A[],int n)
	{
		for(int gap=n/2;gap>0;gap=gap/2)//步长
		{
			for(int i=gap;i<n;i++)
			{
				if(A[i] < A[i-gap])
				{
					int k;
					int tmp = A[i];
					for(k = i-gap;k >=0 && A[k]>tmp;k-=gap)
					{
						//比tmp大的,向后移位
						A[k+gap]=A[k];
					}
					//此时A[k]比tmp小,插入位置在k+gap
					A[k+gap] = tmp;
				}
			}
		}
	}

	//思路3.用交换的思想,可以不用考虑向后移位的问题。
	//如果A[i]>A[i-1],则不动;否则,交换,i--,再比较A[i]和A[i--],直到A[i]>A[i-1]为止。
	void shellSort3(int A[],int n)
	{
		for(int gap = n/2;gap >0;gap/=2)
			for(int i=gap;i<n;i++)
				for(int j=i-gap;j>=0 && A[j]>A[j+gap];j-=gap)
					swap(A[j],A[j+gap]);
	}

	//选择排序
	//与插入排序类似,都分为有序区和无序区。不同的是,插入排序是将第一个元素插入有序区形成更大的有序区;而选择排序是从无序区找出最小,放到无序区的最前面(有序区的最后面)。
	//最开始都是无序的,选择一个最小的与第一个交换;指向第二个,选择后面最小的与第二个交换。。。。
	void selectSort(int A[],int n)
	{
		for(int i=0;i<n;i++)
		{
			int minIdx = i;
			for(int j=i+1;j<n;j++)
			{
				if(A[j]<A[minIdx])
				{
					minIdx = j;
				}
			}
			swap(A[i],A[minIdx]);
		}
	}

	//归并排序
	//递归+合并。当一个数组左边和右边有序,那么合并这两个有序数就完成了排序。如何让左右两遍都有序?用递归!递归下去,合并上来就是归并排序。
	void mergeArray(int a[],int first,int mid,int last,int tmp[])//将两个有序数组a[first,mid]和a[mid,last]合并。
	{
		int i = first,j = mid +1;
		int k=0;
		while( i<=mid && j<=last )
		{
			if(a[i]<=a[j])
			{
				tmp[k++] = a[i++];
			}
			else
			{
				tmp[k++] = a[j++];
			}
		}

		while(i <= mid)
		{
			tmp[k++] = a[i++];
		}

		while(j <= last)
		{
			tmp[k++] = a[j++];
		}

		for(i =0;i<k;i++)
		{
			a[first+i] = tmp[i];
		}
	}

	void mergeSort(int a[],int first,int last,int tmp[])
	{
		if(first < last)
		{
			int mid = (first+last)/2;
			mergeSort(a,first,mid,tmp);//左边有序
			mergeSort(a,mid+1,last,tmp);//右边有序
			mergeArray(a,first,mid,last,tmp);//将两个有序数列合并
		}
	}

	//快速排序。挖坑填数字+分治法。
	//1.i=first,j=last.选一个基准数(一般选第一个)。将其挖出来,形成一个坑a[i];
	//2.从后向前j--找到一个比它小的数,找到后挖出来填到之前的a[i]的坑中,这时候形成一个新坑a[j];
	//3.从前向后i++找到一个比它大的数,找到之后填到此前的a[j]坑中;
	//4.重复,直到i==j,将基准数填入a[i]中。至此,基准点左边的都比它小,右边的都比它大。
	//5.以基准点为中心,分成两个序列,重复上面的步骤。
	void quickSort(int a[],int first,int last)
	{
		if(first < last)
		{
			int i=first,j=last,value=a[first];
			while(i<j)
			{
				//从左边找到第一个小于value的数字,填到之前a[i]位置,形成一个新坑a[j]
				while(i<j&&a[j]>value)
					j--;
				if(i<j)
					a[i++] = a[j];

				//从右边找到第一个大于value的数字,填到之前a[j]的位置上,形成一个新坑a[i]
				while(i<j&&a[i]<value)
					i++;
				if(i<j)
					a[j--]=a[i];
			}

			//将value填到a[i]中
			a[i] = value;

			//以基准点为中心分开为两个序列,重复上面步骤
			quickSort(a,first,i);//递归处理
			quickSort(a,i+1,last);
		}
	}

	//堆排序
	//二叉堆。父节点总是大于等于(小于等于)子节点。每一个左右子树都是一个二叉堆。父节点大于子节点的叫做最大堆,父节点小于子节点,叫做最小堆。
	//二叉堆可以用数组表示。找父节点下标,(i-1)/2;左右子节点下标,2*i+1和2*i+2
	//堆的插入。每次插入都是放到数组最后。它的父节点到根节点都是有序的,任务就是将新数据插入到有序数组中。(插入排序)
	//堆的删除。每次删除第0个数据,然后将最后一个数据的值赋给根节点,自上向下调整树。相当于从根节点将一个数据下沉的过程。
	//堆排序。1)首先堆化数组。2)A[0]与A[n-1]交换,再对A[0,n-2]重新恢复堆。第二次,将A[0]与A[n-2]交换,对[0,n-3]重新恢复堆,一直重复道A[0]与A[1]交换。
	//这样每次最小的就放到了后面的有序序列。操作完成之后,整个数组就有序了。
	
	//从第i个节点整理,从上到下。n为节点总数。
	void heapFixDown(int a[],int i,int n)
	{
		int tmp = a[i];
		int j = 2*i+1;//i的左子节点
		while(j < n)
		{
			//先找到子节点中最小的
			if(j+1 < n && a[j+1] < a[j])
			{
				j++;
			}

			//如果子节点中最小的都比根节点小,啥也不用做
			if(a[j]>=tmp)
				break;

			//将较小的子节点往上移动,替换它的父节点
			a[i] = a[j];
			i=j;
			j=2*i+1;
		}
		a[i]=tmp;
	}

	//建立最小堆
	void createMinHeap(int a[],int n)
	{
		for(int i=n/2-1;i>=0;i--)
		{
			heapFixDown(a,i,n);
		}
	}

	//堆排序
	void heapSort(int a[],int n)
	{
		createMinHeap(a,n);		
		for(int i=n-1;i>=1;i--)
		{
			swap(a[i],a[0]);
			heapFixDown(a,0,i);
		}
	}
};

void main()
{
	int A[] = {7,2,3,5,9,8,10,20,15};
	int n = sizeof(A)/sizeof(int);

	printf("The original array is:\n");
	for(int i=0;i<n;i++)
	{
		printf("%d ",A[i]);
	}
	printf("\n");

	Solution *Sol = new Solution();
	//Sol->bubbleSort3(A,n);
	//Sol->selectSort(A,n);

	//int *p = new int[n];
	//if (p==NULL)
		//return;
	//Sol->mergeSort(A,0,n-1,p);
	//delete[] p;

	Sol->heapSort(A,n);
	printf("The latest array is:\n");
	for(int i=0;i<n;i++)
	{
		printf("%d ",A[i]);
	}
	printf("\n");
	delete Sol;
}


 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值