归并排序的实现

       最近工作中要用到排序,当然要选择O(nlgn)时间复杂度的算法,还要求是稳定的,周末就温习了一下排序算法,归并排序刚好能满足。自己也想练练手,就先实现了简单的对递归版本,之后实现了非递归的版本。它的空间复杂度为O(n)。  因为递归版本会使用函数堆栈,深度受到栈内存的限制,所以数据量不能太大,需要注意下。

//【归并排序--递归版本】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>


void swap(int *a, int *b)
{
	int t = *a;
	*a = *b;
	*b = t;
}


void merge(int a[], int m, int n)
{
	int *b = (int*)malloc(sizeof(int)*n);
	assert(b != NULL);
	memcpy(b, a, sizeof(int)*n);

	int i = 0, j = m, k = 0;
	while(i < m && j < n)
	{
		if (b[i] <= b[j])
		{
			a[k++] = b[i];
			i++;
		}
		else
		{
			a[k++] = b[j];
			j++;
		}
	}

	if (i < m)
	{
		while (i < m) a[k++] = b[i++];
	}
	else
	{
		while (j < n) a[k++] = b[j++];
	}
}

void mergeSort(int a[], int n)
{
	if (n <= 1) return;
	if (n == 2) 
	{
		if (a[0] > a[1])
			swap(a+0, a+1);
		return;
	}

	int m = n/2;
	mergeSort(a, m);
	mergeSort(a + m, n - m);
	merge(a, m, n);
}



void setRandData(int a[], int n)
{
	srand(time(NULL));
	for (int i = 0; i < n; i++)
	{
		a[i] = rand();
	}
}

int main()
{
	const int N = 10000000;
	int *a = (int*)malloc(sizeof(int) * N);
	assert(a != NULL);

	setRandData(a, N);
	//for (int i = 0; i < N; i++)
	//{
	//	printf("%d\t", a[i]);
	//}
	printf("\n");

	clock_t t0 = clock();
	mergeSort(a, N);
	clock_t t1 = clock();
	printf("Take time %d ms\n", t1 - t0);


	for (int i = N/2; i < N && i < (N/2 + 200); i++)
	{
		printf("%d    ", a[i]);
	}
	system("pause");
	return 0;
}

//【归并排序--非递归版本】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>

inline int min(int a, int b)
{
	return a < b ? a : b;
}


void setRandData(int a[], int n)
{
	srand(time(NULL));
	for (int i = 0; i < n; i++)
	{
		a[i] = rand() * rand();
	}
}

void mergeSort(int a[], int n)
{
	int i, j, t, start1, end1, start2, end2, len;
	int *b = (int*)malloc(sizeof(int) * n);
	assert(b != NULL);

	len = 1;	//len为每次分块的大小,即按照1,2,4,6,8,...,n增长
	while (len < n)
	{
		t = 0;
		i = 0;
		j = i + len;
		while (j != n)
		{
			//start1,end1,start2,end2用于表示进行比较的两个数据块下标,
			//坐标范围分别为[start1,end1),[start2,end2)。
			start1 = min(n, i);
			end1   = min(n, i + len);
			start2 = min(n, i + len);
			end2   = min(n, i + len + len);

			i = start1;
			j = start2;
			while (i < end1 && j < end2)
			{
				if (a[i] <= a[j]) 
				{
					b[t++] = a[i++];
				}
				else
				{
					b[t++] = a[j++];
				}
			}

			if (i < end1)
			{
				while (i < end1)
					b[t++] = a[i++];
			}
			else
			{
				while (j < end2)
					b[t++] = a[j++];
			}
			//assert(i == end1 && j == end2 && t == end2);
			i = t;
		}
		len = min(n, len * 2);
		memcpy(a, b, sizeof(int) * n);
	}
	free(b);
}


int main()
{
	const int N = 100000000;
	int *a = (int*)malloc(sizeof(int) * N);
	assert(a != NULL);

	setRandData(a, N);
	//for (int i = 0; i < N; i++)
	//{
	//	printf("%d\t", a[i]);
	//}
	printf("\n");

	clock_t t0 = clock();
	mergeSort(a, N);
	clock_t t1 = clock();
	printf("Take time %d ms\n", t1 - t0);


	for (int i = N/2; i < N && i < (N/2 + 100); i++)
	{
		printf("%d    \n", a[i]);
	}
	system("pause");
	return 0;
}



【归并排序-使用模板】

mergesort.h

#ifndef __MERGESORT_H
#define __MERGESORT_H


namespace MyNamespace
{
	typedef int (*Comparer)(const void *a, const void *b);

	template <typename T> 
	int defaultCompare(T *a, T *b)
	{
		if (*a == *b) return 0;
		return *a < *b ? -1 : 1;
	}

	template <typename T> 
	void arrayCopy(T *a, const T *b, int n)
	{
		while (--n >= 0) a[n] = b[n];
	}

	inline int minIndex(int a, int b)
	{
		return a < b ? a : b;
	}

	template <typename T>
	int mergeSort(T a[], int n, Comparer comparer)
	{
		T *b = NULL;
		int i, j, t, start1, end1, start2, end2, len;
		int cmpResult;

		b = new T[n];
		if (b == NULL) return -1;


		//len为每次分块的大小,即按照1,2,4,6,8,...,n增长
		len = 1;
		while (len < n)
		{
			t = 0;
			i = 0;
			j = i + len;
			while (j != n)
			{
				//start1,end1,start2,end2用于表示进行比较的两个数据块下标,
				//两个分块的下标范围为[start1,end1),[start2,end2)。
				start1 = minIndex(n, i);
				end1   = minIndex(n, i + len);
				start2 = minIndex(n, i + len);
				end2   = minIndex(n, i + len + len);

				//i,j分别表示当前进行比较的两个元素的下标
				i = start1;
				j = start2;
				while (i < end1 && j < end2)
				{
					if (comparer != NULL)
						cmpResult = comparer(a+i, a+j);
					else
						cmpResult = defaultCompare(a+i, a+j);

					b[t++] = (cmpResult <= 0) ?  a[i++] : a[j++];
				}

				if (i < end1)
				{
					while (i < end1)
						b[t++] = a[i++];
				}
				else
				{
					while (j < end2)
						b[t++] = a[j++];
				}
				//assert(i == end1 && j == end2 && t == end2);
				i = t;
			}
			len = minIndex(n, len * 2);
			arrayCopy(a, b, n);
		}

		delete []b;
		b = NULL;
		return 0;
	}

	template <typename T>
	int mergeSort(T a[], int n)
	{
		return mergeSort(a, n, NULL);
	}

};

#endif //__MERGESORT_H



main.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include "mergesort.h"

using namespace std;

int myComparer(const int *a, const int *b)
{
		if (*a == *b) return 0;
		return *a < *b ? -1 : 1;
}

int myComparer2(const void *a, const void *b)
{
		if (*(int*)a == *(int*)b) return 0;
		return *(int*)a < *(int*)b ? -1 : 1;
}


struct S
{
	int a;
	string str;

	bool operator== (const S &o)
	{
		return (a == o.a) && (str == o.str);
	}

	bool operator< (const S &o)
	{
		if (a != o.a) return a < o.a;
		return str < o.str;
	}
};



int main()
{
	S ss[] = {
		{2, "ok"}, 
		{1, "hi"},
		{4, "aa"}
	};

	int a[] = {3,2,7,9,8};
	//MyNamespace::mergeSort(a, 5, (MyNamespace::Comparer)myComparer);
	MyNamespace::mergeSort(a, 5, myComparer2);
	printf("%d %d %d %d %d\n", a[0], a[1], a[2], a[3], a[4]);

	//
	//a[1] = 100;
	//MyNamespace::mergeSort(a, 5);
	//printf("%d %d %d %d %d\n", a[0], a[1], a[2], a[3], a[4]);

	MyNamespace::mergeSort(ss, 3);
	printf("%d,%s %d,%s\n", ss[0].a, ss[0].str.c_str(), ss[1].a, ss[1].str.c_str());

	system("pause");
	return 0;
}

输出

2 3 7 8 9
1,hi 2,ok
请按任意键继续. . .


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++中的归并排序是一种经典的排序算法,它采用分治的思想,将待排序的数组不断地分割成更小的子数组,然后再将这些子数组合并成有序的数组。下面是C++中归并排序实现: ```cpp #include <iostream> using namespace std; // 合并两个有序数组 void merge(int arr[], int left, int mid, int right) { int n1 = mid - left + 1; int n2 = right - mid; // 创建临时数组 int L[n1], R[n2]; // 将数据复制到临时数组 for (int i = 0; i < n1; i++) L[i] = arr[left + i]; for (int j = 0; j < n2; j++) R[j] = arr[mid + 1 + j]; // 合并临时数组 int i = 0, j = 0, k = left; while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } // 复制剩余元素 while (i < n1) { arr[k] = L[i]; i++; k++; } while (j < n2) { arr[k] = R[j]; j++; k++; } } // 归并排序 void mergeSort(int arr[], int left, int right) { if (left < right) { int mid = left + (right - left) / 2; // 分割数组 mergeSort(arr, left, mid); mergeSort(arr, mid + 1, right); // 合并数组 merge(arr, left, mid, right); } } int main() { int arr[] = {12, 11, 13, 5, 6, 7}; int n = sizeof(arr) / sizeof(arr[0]); cout << "原始数组:"; for (int i = 0; i < n; i++) cout << arr[i] << " "; cout << endl; mergeSort(arr, 0, n - 1); cout << "排序后的数组:"; for (int i = 0; i < n; i++) cout << arr[i] << " "; cout << endl; return 0; } ``` 这段代码实现归并排序算法。首先,我们定义了一个`merge`函数,用于合并两个有序数组。然后,我们定义了`mergeSort`函数,用于递归地分割和合并数组。最后,在`main`函数中,我们创建一个待排序的数组,并调用`mergeSort`函数进行排序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

piaopiaolanghua

感谢鼓励,再接再厉!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值