排序算法

本文深入探讨了排序算法,包括其原理、实现方式以及应用场景。通过对不同排序算法的比较,帮助读者理解它们的效率和适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

排序算法

#pragma once

void InsertSort(int* array, int size);//直接插入排序
void InsertSort_op(int* array, int size);//直接插入排序(嵌套二分查找)
void ShellSort(int* array, int size);//希尔排序
void Swap(int* pLeft, int* pRight);//交换
void SelectSort(int* array, int size);//选择排序
void SelectSort_op(int* array, int size);//选择排序优化
void Print(int* array, int size);//打印
void Test();//测试
#include "Sort.h"
#include <stdio.h>
#include <malloc.h>
#include <string.h>

//直接插入排序:比较次数多,每次比较O(N)
//          1.时间复杂度为 O((N-1)*N)=O(N^2)
//          2.空间复杂度为 O(1)
//          3.稳定性:稳定
//适用场景:1.接近有序,使得搬移的次数减少
//          2.元素个数较少
void InsertSort(int* array, int size)
{
	int i = 0;
	int end = 0;
	for (i=1; i < size; i++)
	{
		end = i - 1;
		int key = array[i];
		//搬移元素
		while (end >= 0 && key < array[end])
		{
			array[end + 1] = array[end];
			end--;
		}
		//插入
		array[end + 1] = key;
	}
}

//直接插入排序(嵌套二分查找):比较次数减少 O(logN)
//              1.时间复杂度为:O((N-1)*logN)=O(NlogN)
//              2.空间复杂度为:O(1)
//              3.稳定性:稳定
void InsertSort_op(int* array, int size)
{
	int i = 0;
	for (i = 1; i < size; i++)
	{
		int end = i - 1;
		int left = 0;
		int right = end;
		int mid = 0;
		int key = array[i];
		//二分查找元素要插入的位置
		while (left <= right)
		{
			mid = left + ((right - left) >> 1);
			if (key < array[mid])
				right = mid - 1;
			else
				left = mid + 1;
		}
		//搬移元素
		while (end >=left)
		{
			array[end + 1] = array[end];
			end--;
		}
		//插入
		array[left] = key;
	}
}

//希尔排序:又称缩小增量排序,是对直接插入排序的优化
//         1.时间复杂度为:O(N^1.25)--O(1.6N^1.25) == O(N^1.3)
//         2.空间复杂度为:O(1)
//         3.稳定性:不稳定
//适用场景:1.顺序杂乱
//          2.元素个数较多
void ShellSort(int* array, int size)
{
	int i = 0;
	int gap = size;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		for (i = gap; i < size; i++)
		{
			int end = i - gap;
			int key = array[i];
			//搬移元素
			while (end >= 0 && key < array[end])
			{
				array[end + gap] = array[end];
				end -= gap;
			}
			//插入元素
			array[end + gap] = key;
		}
	}
}
//交换
void Swap(int* pLeft, int* pRight)
{
	int temp = *pLeft;
	*pLeft = *pRight;
	*pRight = temp;
}


//选择排序
void SelectSort(int* array, int size)
{
	int i = 0;
	int j = 0;
	int maxpos = 0;
	for (; i < size - 1; i++)
	{
		maxpos = 0;
		for (j = 1; j < size-i; j++)
		{
			if (array[maxpos] < array[j])
				maxpos = j;
		}
		if (maxpos != size - 1 - i)
			Swap(&array[maxpos], &array[size - 1 - i]);
	}
}

void SelectSort_op(int* array, int size)
{
	int i = 0;
	int begin = 0;
	int end = size - 1;
	int maxpos = 0;
	int minpos = 0;

	while (begin < end)
	{
		minpos = begin;
		maxpos = begin;
		i = begin + 1;
		while (i <= end)
		{
			if (array[maxpos] < array[i])
				maxpos = i;
			if (array[minpos]>array[i])
				minpos = i;
			i++;
		}
		
		if (minpos != begin)
			Swap(&array[minpos], &array[begin]);
		//9 2 3 7 6 5 4 8 0
		if (maxpos == begin)
			maxpos = minpos;
		if (maxpos != end)
			Swap(&array[maxpos], &array[end]);
		begin++;
		end--;
	}
}

//堆排序(大堆----升序)     (小堆----降序)
//此为大堆---> 升序
void AdjustDownHeap(int* array, int size,int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		//找左右孩子中最大的
		if (child+1<size && array[child + 1] > array[child])
			child += 1;
		//将最大的孩子节点和其双亲比较
		if (array[parent] < array[child])
		{
			Swap(&array[parent], &array[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			return;
	}
	
}
//创建堆
void CreatHeap(int* array, int size)
{
	//找倒数第一个非叶子节点
	int root = (size - 2) >> 1;
	//递归调用向下调整
	for (; root >= 0; root--)
		AdjustDownHeap(array, size, root);
}

//快排:先排序后划分
//空间复杂度:O(logN)(一般情况下,它所开辟的空间相当于一棵二叉平衡树,所以空间复杂度=树的高度)
//稳定性:不稳定
//时间复杂度:
//如果每次取得基准值key刚好是该数组中的中间大小的值,则时间复杂度最好为O(NlogN) (划分了logN次,每次划分的时间为N);
//但是,当数组有序或接近有序时,取得key就是最大或最小值,则时间复杂度最坏为O(N^2);
//所以,为了避免出现此种情况,影响快排的效率,给数组3个指针,取这三个数的中间值
int GetMidDataIndex(int* array, int left, int right)
{
	int mid = left + ((right - left) >> 1);
	if (array[left] < array[right])
	{
		if (array[mid] < array[left])
			return left;
		else if (array[mid]>array[right])
			return right;
		else
			return mid;
	}
	else//array[left]>array[right]
	{
		if (array[mid] > array[left])
			return left;
		else if (array[mid] < array[right])
			return right;
		else
			return mid;
	}
}
//1.hoare版本
//
int Partion(int* array, int left, int right)//key为基准,一般取数组最右边的值
{
	int keyIndex = GetMidDataIndex(array, left, right);
	if (keyIndex != right - 1)
		Swap(&array[keyIndex], &array[right - 1]);
		
	int key = array[right-1];

	int begin = left;
	int end = right - 1;
	
	while (begin < end)
	{
		while (begin < end && array[begin] <= key)
			begin++;
		while (begin < end && array[end] > key)
			end--;
		if (begin < end)
			Swap(&array[begin], &array[end]);
	}
	if (begin!=right-1)
		Swap(&array[begin], &array[right - 1]);
	return begin;
}
//快排的递归算法
void QuickSort(int* array,int left,int right)//区间是前闭后开[)
{
	if (right - left < 16)
		//如果数组中元素个数少,则采用插入排序效率高
		InsertSort(array, right - left);
	else
	{
		int div = Partion(array, left, right);
		QuickSort(array, left, div);
		QuickSort(array, div+1, right);
	}
}
//2.挖坑法
int Partion2(int* array, int left, int right)
{
	int keyIndex = GetMidDataIndex(array, left, right);
	if (keyIndex != right - 1)
		Swap(&array[keyIndex], &array[right - 1]);

	int key = array[right - 1];
	int begin = left;
	int end = right - 1;
	
	while (begin<end)
	{
		while (begin < end && array[begin] <= key)
			begin++;
		if (begin < end)
		{
			array[end] = array[begin];
			end--;
		}
		
		while (begin<end && array[end]>key)
			end--;
		if (begin < end)
		{
			array[begin] = array[end];
			begin++;
		}
	}
	if (begin != right - 1)
		array[begin] = key;
	
	return begin;
}
//3.前后指针法
int Partion3(int* array, int left, int right)
{
	int keyIndex = GetMidDataIndex(array, left, right);
	if (keyIndex != right - 1)
		Swap(&array[keyIndex], &array[right - 1]);

	int key = array[right - 1];
	int cur = left;
	int prev = cur - 1;
	
	while (cur<right)
	{
		while (array[cur] <= key && ++prev != cur)
			Swap(&array[cur], &array[prev]);
		cur++;
	}
	if (++prev != right)
		Swap(&array[prev], &array[right - 1]);

	return prev;
}

//归并排序:先划分后排序
//递归算法: 时间复杂度O(NlogN)  空间复杂度O(logN)   稳定性:稳定

//合并两个有序数组到新的数组中并且结果是有序的
void MergeData(int* array, int left, int mid, int right, int* temp)
{
	int begin1 = left;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = right;
	int Index = 0;

	//合并两个有序数组到新的数组中并且结果是有序的
	while (begin1 < end1 && begin2 < end2)
	{
		if (array[begin1] <= array[begin2])
			temp[Index++] = array[begin1++];
		if (array[begin2] < array[begin1])
			temp[Index++] = array[begin2++];
	}

	while (begin1 < end1)
		temp[Index++] = array[begin1++];
	while (begin2 < end2)
		temp[Index++] = array[begin2++];
}

void _MergeSort(int* array, int left, int right,int* temp)
{
	if (right - left < 16)
		InsertSort(array, right - left);
	else
	{
		int mid = left + ((right - left) >> 1);
		_MergeSort(array, left, mid, temp);
		_MergeSort(array, mid+1, right, temp);
		MergeData(array, left, mid, right, temp);
		memcpy(array + left, temp, sizeof(array[0])*(right - left));
	}
}
void MergeSort(int* array, int size)
{
	int* temp = (int*)malloc(sizeof(int)*size);
	if (NULL == temp)
		return;

	_MergeSort(array, 0, size, temp);

	free(temp);
}
//非递归算法: 空间复杂度为O(N)   时间复杂度为O(NlogN)
//分析:先两两排序,再一组4个进行排序......
void MergeSort_op(int* array, int size)
{
	int gap = 1;
	int i;

	int* temp = (int*)malloc(sizeof(int)*size);
	if (NULL == temp)
		return;
	while (gap < size)
	{
		int left, right, mid;
		for (i = 0; i < size; i += 2 * gap)
		{
			left = i;
			mid = left + gap;
			if (mid > size)
				mid = size;
			right = mid + gap;
			if (right > size)
				right = size;

			//排序
			MergeData(array, left, mid, right, temp);
		}
		//拷贝回原空间
		memcpy(array, temp, sizeof(array[0])*size);
		//更新gap以2的倍数增长
		gap *= 2;
	}
	free(temp);
}

//C++版的归并排序:时间复杂度为O(NlogN),空间复杂度为O(N)
//利用归并的方法进行排序完成两个主要功能即可:拆分和合并
//拆分用到了比较好的方法就是利用快慢指针进行,每次找到链表的中间部分进行拆解
//合并可以利用两种方式:一种是非递归的方法另一种是递归的方法,都是可以做的
//这里用递归的方法,理解起来比较简单
#include <iostream>
using namespace std;

Definition for singly-linked list.
struct ListNode 
{
	int val;
	ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
	ListNode* MergeList(ListNode* list1, ListNode* list2)
	{
		if (list1 == NULL)
			return list2;
		if (list2 == NULL)
			return list1;
		ListNode *pHead = NULL;
		if (list1->val < list2->val)
		{
			pHead = list1;
			pHead->next = MergeList(list1->next, list2);
		}
		else
		{
			pHead = list2;
			pHead->next = MergeList(list2->next, list1);
		}
		return pHead;
	}

	ListNode* sortList(ListNode* head)
	{
		if (head == NULL || head->next == NULL)
			return head;
		ListNode* slow = head;
		ListNode* fast = head->next;
		while (fast && fast->next)
		{
			fast = fast->next->next;
			slow = slow->next;
		}
		ListNode* headb = slow->next;
		slow->next = NULL;
		return MergeList(sortList(head), sortList(headb));
	}
};


//非比较排序:
//一.计数排序
//步骤: 1:确定数据范围——分配空间
//       2:统计每个元素出现的次数
//       3:根据统计的结果将序列回收到原来的序列中
void CountSort(int* array, int size)
{
	int i = 0;
	int maxValue = array[0];
	int minValue = array[0];
	int Index = 0;
	int* pcount = NULL;
	//遍历数组得到数组的最大值和最小值
	for (i = 1; i < size; i++)
	{
		if (maxValue < array[i])
			maxValue = array[i];
		if (minValue > array[i])
			minValue = array[i];
	}
	//确定所要分配空间的大小
	int rang = maxValue - minValue + 1;
	pcount = (int*)malloc(sizeof(int)*rang);
	if (NULL == pcount)
		return;
	memset(pcount, 0, sizeof(int)*rang);//将新空间置0
	//统计每个元素出现的次数
	for (i = 0; i < size; i++)
	{
		pcount[array[i] - minValue]++;//?
	}
	//回收数据
	i = 0;
	while (i < rang)
	{
		while (pcount[i]--)
			array[Index++] = i + minValue;
		i++;
	}

	free(pcount);
}
//二.基数排序


//打印
void Print(int* array, int size)
{
	int i = 0;
	for (; i < size; i++)
	{
		printf("%d  ", array[i]);
	}
	printf("\n");
}
//测试
void Test()
{
	int array[] = { 9, 0, 4, 8, 7, 2, 3, 1, 6 ,5};
	int size = sizeof(array) / sizeof(array[0]);
	Print(array, size);
	/////*InsertSort(array, size);
	////Print(array, size);

	////InsertSort_op(array, size);
	////Print(array, size);*/

	////ShellSort(array, size);
	////Print(array, size);

	//SelectSort(array, size);
	//Print(array, size);

	/*SelectSort_op(array, size);
	Print(array, size);*/

	/*AdjustDownHeap(array, size, 0);
	Print(array, size);*/

	CountSort(array, size);
	Print(array, size);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值