快速排序 归并排序【递归实现】

实现快速排序

方法一:hoare

思想

(排升序总体思路

  • 1.先从数据中取出一个数作为基准数。
  • 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边(单趟排序)。
  • 3.再对左右区间重复第二步,直到各区间只有一个数。 

 快速排序 归并排序【递归实现】_第1张图片

排升序n为数据数量   细分思路

 假设我们选了最前面的数据为基数(key)

  1. 创建两个变量left和right,left是最前面的数的下标,right是最后面的那个数下标
  2. 再让left和right分别往前面走,这里由于选的是最前面的为key,那么这里要让right先走
  3. right往前走,去找比key小的数,找到后,right暂停往前走
  4. 再让left往前面走,去找到比key大的数,找到后,left暂停往前走
  5. 那么此时就让 left 和 right 的下标所对应数据,进行交换.
  6. 交换往后,再让left和right重复上述操作
  7. 当 left 和right 相遇时,本次单趟排序结束,并记录下此刻相遇的位置下标为m
  8. 然后我们将区间分为 [0,m-1]  [m+1,n-1] ,在对两个区间分别进行单趟排序
  9. 我们再对两个区间进行一次划分,划分好后,又重复一次单趟排序
  10. 再重复分区,单趟排序操作,直到各区间只有一个元素时,就结束了快排
  1. 为什么选最前面的作为基数后,要让right要走,而不是让left先走? 

问题一:​这是为了防止 出现两者相遇处的数值比key还大

代码实现 

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

int PartSort(int* a, int left, int right)//单趟排序
//1.先从数列中取出一个数作为基准数。
//2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
{
	int key = a[left];
	int keyindex = left;
	while (left < right)
	{
        //这里要保证left= key)//找小
		{
			--right;
		}
		while (left < right && a[left] <= key)//找大
		{
			++left;
		}
		Swap(&a[left], &a[right]);
	}
	swap(&a[keyindex], &a[left]);//&a[right]

	return  left;//return right;
}

void QuickSort1(int* a, int left, int right)
{
	assert(a);
	if (left > right)
	{
		return;
	}
	int div = PartSort(a, left, right);
	//3.再对左右区间重复第二步,直到各区间只有一个数。
	QuickSort(a, left, div - 1);
	QuickSort(a, div + 1, right);

}

 方法二:挖坑法

思路 (排升序)

  1. 先在数据里找一个数据,将其确定为坑位(key),这里将最后面的位置作为坑位,
  2. 创建好两个变量begin,end,这两个变量是用来存数据的下标
  3. 将数值key的下标赋给begin,再将最后位置的下标赋给end,
  4. begin往前去找比key大的数据,如果没有找到,那么就往前面去找
  5. 找到后,那么begin就暂停往前,并且交换keybegin的数据
  6. 此时begin的位置就是新的坑位,此刻begin前面的数小于key
  7. 再让end往前去找比key小的,找到就交换,一次排序结束
  8. 不断重复上述操作,直到,两者相遇,就结束并返回现在相遇的位置下标 m,
  9. 此刻m位置前面的数据小于key,m后面的>=key
  10. 然后在对数据进行分区 [0,m-1] m [m+1,n-1]
  11. 然后,在对区间 [0,m-1] [m+1,n-1]进行上面相同的操作
  12. 不断的分区,再排序。直到区间里只有一个数据时,就完成快排

 代码实现

//方法2:挖坑法 排升序
void PartSort2(int* a, int left, int right)
{
	assert(a);
	int key = a[right];//此时right是一个坑
	while (left < right)
	{
		while (left < right && a[left] <= key)
			//找大
		{
			++left;
		}
		a[right] = a[left];//填坑,此时也创建了新的坑left

		while (left < right && a[right] >= key)
			//找小
		{
			--right;
		}
		a[left] = a[right];//在填坑,在创建新坑right
	}
	a[left] = key;//a[right]=key;
	return left;//return right;
}
void QuickSort2(int* a, int left, int right)
{
	assert(a);
	if (left > right)
	{
		return;
	}
	int div = PartSort2(a, left, right);
	//3.再对左右区间重复第二步,直到各区间只有一个数。
	QuickSort2(a, left, div - 1);
	QuickSort2(a, div + 1, right);

}

方法三:前后指针法

思路(排升序)

前提:初始的begin是最前面位置的下标,end是最后一个位置的下标

  1. 先在数据里找到一个基数(key)
  2. 再创建两个变量 prev cur,prev=begin-1  cur=begin
  3. cur去找比key小的数,找到了,那么cur就不暂停往前,如果比key大,就继续往前面走
  4. 然后++prev,再去交换prev对应的数据和cur对应的数据
  5. 再继续重复上面操作,直到cur遍历完整个数据,那么再++prev
  6. 交换prev和key所对应的数据,并返回此时prev位置的下标m,该单趟排序结束
  7. 再对区间 [0,m-1] [m+1,n-1](n为数据数目)进行上述操作
  8. 当区间被划分为只有一个元素是就完成了快排

 代码

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//前后指针方法  排升序
int PartSort3(int* a, int begin, int end)
{
	int prev = begin - 1;
	int cur = begin;
	int keyindex = end;
	while (cur <= end)
	{
		if (a[cur] < a[keyindex] && ++prev != cur)//找小
		{
			Swap(&a[cur], &a[prev]);
		}
		++cur;
	}
	Swap(&a[++prev], &a[keyindex);
	return prev;
}
void QuickSort3(int* a, int left, int right)
{
	assert(a);
	if (left > right)
	{
		return;
	}
	int div = PartSort3(a, left, right);
	QuickSort3(a, left, div - 1);
	QuickSort3(a, div + 1, right);

}

实现归并排序

思路

该算法是采用分治法 (Divide and Conquer)的一个非常典型的应用。

将已有序的子序列合并,得到完全有序的序列

先使每个子序列有序,再使子序列段间有序。

若将两个有序表合并成一个有序表,称为二路归并。

 细分步骤

n是数数组里数据数目 排升序

  1. 先malloc一个大小为n的整型数组tmp
  2. 将数组进行划分区间,begin=0 end=n-1 mid=(begin+end)/2 [begin ,mid]  [mid+1 ,end]
  3. 然后继续对这两个区间继续划分,得到4个区间
  4. 再不断重复分区操作,当每个区间只有一个数据时,分区结束,并开始返回,不在往下分
  5. 然后在不断比较两区间的数,将它们从小往大依次放入tmp数组里
  6. 当有一个区间已全部完成,那么在将未完成的剩下区间拷贝到tmp的后面位置处
  7. 最后将数组tmp拷贝给原数组

 快速排序 归并排序【递归实现】_第2张图片

 代码实现

快速排序 归并排序【递归实现】_第3张图片

void _MergeSort(int* a,int* tmp, int left, int right)
{
	int mid = (left + right) / 2;
	_MergeSort(a, tmp, left, mid);
	_MergeSort(a, tmp, mid+1, right);
	
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int index = begin1;//记录下标
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] <= a[begin2])
		{
			tmp[index++] = a[begin1++];
		}
	    else if(a[begin1]>a[begin2])
		{
			tmp[index++] = a[begin2++];
		}
	}

	while (begin1 < end1)
		tmp[index++] = a[begin1++];

	while (begin2 < end2)
		tmp[index++] = a[begin2++];

	for (int i = left; i <= right; i++)
	{
		a[i] = tmp[i];
	}
}

void MergeSort(int* a, int n)
{
	assert(a);

	int* tmp = (int*)malloc(sizeof(int) * n);
	_MergeSort(a, tmp, 0, n - 1);
    feee(tmp)

}

你可能感兴趣的:(数据结构,算法,数据结构)