数据结构排序汇总

1.插入排序

时间复杂度:o(n^2)

空间复杂度:o(1)

稳定

依次比较后交换


void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void InsertSort(int* a, int size)
{
	int end = 0;
	for (end = 0; end < size-1; end++)
	{
		while (end >= 0)
		{
			int tmp = a[end+1];
			if (a[end+1] < a[end])
			{
				a[end+1] = a[end];
				end--;
			}
			else
			{
				break;
			}
			a[end + 1] = tmp;
		}
	}
}

2.shell排序

时间复杂度:o(n^1.3)

不稳定

将数组进行分组预排序,之后再进行插入排序(gap=1时即为插入排序)

void ShellSort(int* a, int size)
{
	int gap = 2;
	while (gap--)
	{
		
		for (int i = 0; i < size - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end+gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
	
}

3.堆排序

时间复杂度:o(n*logn)

空间复杂度:o(logn)

不稳定

升序建大堆,降序建小堆

先将最大的值与最后一个位置的值进行交换,将最后一个排除在堆外,然后进行堆的调整,选出第二大的元素,再进行交换

void AdjustDwon(int* a, int size, int parent)
{
	//升序建大堆
	int child = parent * 2 + 1;
	while (child < size)
	{
		//找大
		if (child+1<size&&a[child + 1] > a[child])
		{
			child++;
		}
		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
		
	}
}

//o(n*logn)
void HeapSort(int* a, int size)
{
	//建堆
	//child=(parent-1)/2;
	for (int i = (size - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDwon(a, size, i);
	}
	int end = size - 1;
	while(end>0)
	{
		Swap(&a[0], &a[end]);
		AdjustDwon(a, end, 0);
		end--;
	}
}

4.冒泡排序

时间复杂度:o(n^2)

空间复杂度:o(1)

稳定

将元素依次向后比较,选出最大的挪到最后面,缩减比较区间,再选出第二大的元素固定到后面

void BubbleSort(int* a, int size)
{
	int i = 0;
	for (i = 0; i < size; i++)
	{
		int j = 0;
		for (j = 0; j < size - i - 1; j++)
		{
			if (a[j] > a[j+1])
			{
				Swap(&a[j], &a[j+1]);
			}
		}
	}
}

5.选择排序

时间复杂度:o(n^2)

空间复杂度:o(1)

不稳定

遍历数组选出最大的元素和最小的元素,将其固定在头,尾位置。之后缩减遍历的区间,继续找第二大,第二小的元素,再固定到两边。

注意其begin位置与maxi位置相遇时交换会重复

void SelectSort(int* a, int size)
{
	int begin = 0;
	int end = size - 1;
	while (begin<end)
	{
		int maxi = begin;
		int mini = begin;
		for (int i = begin+1; i <= end; i++)
		{
			if (a[i] <a[mini])
			{
				mini = i;
			}
			if (a[i] >a[maxi])
			{
				maxi = i;
			}
		}
		Swap(&a[begin], &a[mini]);
		if (begin == maxi)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
		//Print(a, size);
		end--;
		begin++;
	}
	
}

6.快排

时间复杂度:o(nlogn)

空间复杂度:o(logn)

不稳定

首先选出开始位置为关键元素key,将比它大的元素放到右边(右侧找小),比它小的元素放到其左边(左侧找大),最终将key放到中间位置。然后选出新的key进行左右区间的递归操作

注意key在左侧时要先让右侧开始找小(key在右侧时要先从左侧开始找大)才能保证最后左右两侧相遇的那个位置元素比key小。

void QuickSort(int* a, int left,int right)
{
	if (left > right)
	{
		return;
	}
	int begin = left;
	int end = right;
	int keyi = left;
	while (left < right)
	{
		//右侧找小,key在左侧,先让右侧动来保证最后的a[left]<a[keyi]
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		//左侧找大
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[keyi], &a[left]);
	keyi = left;
	//[begin,keyi-1]keyi[keyi+1,end]
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi+1, end);

}
//快速排序前后指针完整版
void CompleteQuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	int keyi = left;
	int prev = left;
	int cur = left + 1;
	while (cur <= right)
	{
		//cur找小,找到比a[keyi]小的将prev++进行交换(相当于prev找大)
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	//将最后prev位置的值作为新的key
	Swap(&a[keyi], &a[prev]);
	//把prev给keyi将数组分为两个部分开始递归
	keyi = prev;
	//[left,keyi-1]keyi[keyi+1,right]
	CompleteQuickSort(a, left, keyi - 1);
	CompleteQuickSort(a, keyi+1, right);

}
// 快速排序 非递归实现,使用栈实现
#include"Stack.h"
void QuickSortNonR(int* a, int left, int right)
{
	ST st;
	STInit(&st);
	//先入右侧
	STPush(&st, right);
	STPush(&st, left);
	while (!STEmpty(&st))
	{
		//栈先入后出
		int begin = STtop(&st);
		STPop(&st);

		int end = STtop(&st);
		STPop(&st);
		//单趟
		int keyi = begin;
		int prev = begin;
		int cur = begin + 1;
		while (cur <= end)
		{
			if (a[cur] < a[keyi] && ++prev != cur)
			{
				Swap(&a[prev], &a[cur]);
			}
			cur++;
		}
		Swap(&a[keyi], &a[prev]);
		keyi = prev;

		//入keyi右端
		if (keyi + 1 < end)
		{
			//先入右侧
			STPush(&st, end);
			STPush(&st, keyi+1);
		}
		//入keyi左端
		if (keyi - 1 > begin)
		{
			//先入右侧
			STPush(&st, keyi-1);
			STPush(&st, begin);

		}

	}

	STDestroy(&st);
}

7.归并排序

时间复杂度:o(n*logn)

空间复杂度:o(n)

稳定

该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

void _MergeSort(int* a,int* tmp, int left, int right)
{
	if (left == right)
		return;
	
	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 i = left;
	//把两组进行比较,小的插入到tmp数组中,一直到其中一个数组结束
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] <= a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		if(a[begin2]<=a[begin1])
		{
			tmp[i++] = a[begin2++];
		}
	}

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

	}

	while (begin2 <= end1)
	{
		tmp[i++] = a[begin2++];

	}
	//排序结束之后,将数据从tmp拷贝到原数组中
	memcpy(a + left, tmp + left, sizeof(int)*(right - left + 1));

}
void MergeSort(int* a, int left,int right)
{
	int* tmp = (int*)malloc(sizeof(int) * (right-left+1));
	if (tmp == NULL)
	{
		perror("MergeSort():malloc");
		return;
	}
	_MergeSort(a, tmp, left,right);

	//开了空间记得释放
	free(tmp);
	tmp = NULL;
}
//归并排序非递归
void MergeSortNor(int* a, int left, int right)
{
	int* tmp = (int*)malloc(sizeof(int) * (right - left + 1));
	if (tmp == NULL)
	 {
		perror("MergeSortNor():mallloc");
		return;
	 }
	int gap = 1;
	
	while (gap < right+1)
	{
		
		//拷贝到tmp数组的起始位置
		int j = 0;
		//记录比较的起始位置
		for (j=left; j <= right; j = j +2* gap)
		{
				int begin1 = j, end1 = begin1 + gap - 1;
				int begin2 = end1 + 1, end2 = begin2 + gap - 1;
				int i = j;
				if (end1 > right || begin2 > right)
				{
					break;
				}
				if (end2 > right)
				{
					end2 = right;
				}

				while (begin1 <= end1 && begin2 <= end2)
				{
					if (a[begin1] <= a[begin2])
					{
						tmp[i++] = a[begin1++];
					}

					if (a[begin2] <= a[begin1])
					{
						tmp[i++] = a[begin2++];
					}
				}

					while (begin1 <= end1)
					{
						tmp[i++] = a[begin1++];
					}

					while (begin2 <= end1)
					{
						tmp[i++] = a[begin2++];
					}
					//注意拷贝的范围区间
					//j为begin1的位置,end2为两个小区间合并的末尾位置
				memcpy(a + j, tmp + j, sizeof(int) * (end2-j + 1));
		}

		gap = gap * 2;
		
	}
	
}

8.计数排序(非比较排序)

时间复杂度:o(n)

空间复杂度:o(范围)

稳定

1.统计相同元素出现次数
2. 根据统计的结果将序列回收到原来的序列中

void CountSort(int* a, int size)
{
	int min = a[0];
	int max = a[0];
	int i = 0;
	for (i = 1; i < size; i++)
	{
		if (a[i] < min)
		{
			min = a[i];
		}
		if (a[i] > max)
		{
			max = a[i];
		}
	}
	int range = max - min + 1;
	int* tmp = (int*)malloc(sizeof(int) * range);
	if (tmp == NULL)
	{
		perror("CountSort:malloc");
		return;
	}
	//将计数的数组初始化置零
	memset(tmp, 0, sizeof(int)*range);
	for (i = 0; i <size; i++)
	{
		tmp[a[i] - min]++;
	}
	//排序
	int j = 0;
	for (int i = 0; i < range; i++)
	{
		while (tmp[i]--)
		{
			a[j++] = i+min;
		}
	}
	
}

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值