各种排序算法汇总(内排序)

1.直接插入排序,时间复杂度n^2

void InsertSort(int R[], int n)//对含n个元素的数组R排序
{
	int i,j, temp;
	for (int i = 1;i < n;i++)//初始时有序区只有R[0]一个元素
	{
		if (R[i] < R[i - 1])//从最靠近有序区那个元素开始找,找到比有序区最大元素
			//也就是最右边元素更小的元素,然后插入有序区
		{
			temp = R[i];
			j = i - 1;
			while (j >= 0 && R[j] > temp)//有序元素全部右移,直到把temp插入停止
			{
				R[j + 1] = R[j];
				j--;
			}
			R[j+1] = temp;
		}
	}
	for (int i = 0;i < n;i++)
		cout << R[i] << " ";
}

2.折半插入排序,时间复杂度为o(n^2)
折半查找的思想是先二分查找到temp应该插入到有序区的位置,然后再把该位置右边的有序区元素集体右移一位,此时temp的位置已经空了,再把temp插入

void BinInsertSort(int R[], int n)
{
	int i, j, low, high, mid, temp;
	for (int i = 0;i < n;i++)
	{
		if (R[i] < R[i - 1])//找到反序的可以插入有序区的R[i]
		{
			temp = R[i];//先把要插入的元素临时保存起来
			low = 0, high = i - 1;//找到有序区的上下限,然后二分查找插入位置
			while (low <= high)
			{
				mid = (low + high) / 2;
				if (temp < R[mid])
					high = mid - 1;
				else
					low = mid + 1;
			}
			//这里找到的最终位置为high+1,因为当low和high相邻时,此时temp即在low和high中间
			//再进行二分,得到mid=low,然后会temp>=R[mid],所有会有low=mid+1,此时low和high重合
			//再进行二分,会有mid=low=high,然后high=mid-1,此时跳出循环,high的位置往前
			//移动了一步,它右边那个位置应该是temp插入的位置,也就是high+1;
			for (int j = i - 1;j >= high + 1;j--)
				R[j + 1] = R[j];//全体有序区插入位置右边元素右移一位
			R[high + 1] = temp;
		}
	}
}

3.希尔排序(插入排序),就是先把元素分成d组,然后对d组元素进行直接插入排序,时间复杂度n^1.3,然后把d一直减小到1为止,每减小一次进行一次直接插入排序

void ShellSort(int R[], int n)
{
	int i, j, k, temp;
	int d = n / 2;
	while (d > 0)//表示一直到d=1还可以进行各组的直接插入排序
	{
		for (i = d;i < n;i++)//传统希尔排序从1开始,这里从d开始,因为有d组,前面0到d-1一共
			//d个元素分布代表d组序列的有序区初始元素,为一个,每隔d个元素对每组序列进行一次
			//直接插入排序操作,所以循环从d到n是对所有序列进行的完整操作
		{
			temp = R[i];
			j = i - d;
			while (j >= 0 && R[j] > temp)//表示可以插入到该组元素前面的有序区里面
			{
				R[j + d] = R[j];
				j = j - d;
			}
			R[j + d] = temp;
		}
		d = d / 2;
	}
	//这里进行了d从n/2,n/4,n/8一直到1的分组,对每种分组分别进行直接插入排序
	//你也许会有疑问,当n=1时不就是直接对这个序列R[n]进行直接插入排序吗?为什么要加前面的操作
	//事实上,前面这些操作让这个序列R[n]的混乱度不断降低,越到后面所需要进行的操作越少
	//所以这里当进行到d=1然后直接插入排序时,所需要的操作和直接进行直接插入排序所需要的操作少得多
}

4.冒泡排序(交换排序),这里不多做赘述,十分简单,时间复杂度为n^2

void BubbleSort(int R[], int n)
{
	int i, j;
	for(i=0;i<n-1;i++)
		for (j = n - 1;j > i;j--)
		{
			if (R[j] < R[j - 1])
				swap(R[j], R[j - 1]);
		}
}

5.快速排序(交换排序)时间复杂度为nlogn,先找到任意一个元素,一般是第一个元素,然后对该序列进行快速排序,把比temp小的元素放到左边把比temp大的元素放到右边,经过一轮交换,可以把temp放到它最终的位置上,然后再对左右进行排序

int partition(int R[], int start, int over)
{
	int i = start, j = over, temp = R[start];
	while (i < j)//到i=j时temp左边全为小于temp的元素,右边全为大于temp的元素
	{
		while (j > i&& R[j] >= temp)
			j--;//从右边开始直到找到小于temp的元素,循环结束,把该元素R[j]放到temp原来的位置R[i]上面
		R[i] = R[j];
		while (j > i&& R[i] <= temp)
			i++;//从左边开始直到找到比temp大的元素,循环结束,并把R[i]放入已经移走的R[j]位置上
		R[j] = R[i];
	}
	R[i] = temp;//循环结束,得到temp的最终位置在i上,即temp已经归位,在最终的有序位置上面
	return i;
}
void QuickSort(int R[], int start, int over)
{
	int i;
	if (start < over)
	{
		i = partition(R, start, over);//此时已经找到最终应该放入位置i的元素,位置i的元素已经归位
		QuickSort(R, start, i - 1);//递归对左边进行快速排序
		QuickSort(R, i + 1, over);
	}
}

6.简单选择排序(选择排序)时间复杂度n^2

void SelectSort(int R[], int n)
{
	int i, j, temp;
	for (i = 0;i < n - 1;i++)
	{
		temp = i;//这里必须使用temp记录i,因为后面的操作会不停变换temp,但是i是不能被改变的
		for (j = i + 1;j < n;j++)
			if (R[j] < R[temp])
				temp = j;//这个循环找到i后面最小的元素R[temp]
		if (temp != i)//最小的元素不是R[i]本身,那么就交换
		{
			swap(R[i], R[temp]);
		}
	}
}

7.堆排序,这里因为要用堆处理,所有数据是从R[1]到R[n]的,而不是从R[0]开始,首先要采用堆的筛选算法,把堆变成一根最大堆,然后R[1]一定是堆里面最大的元素,此时无序区的最后一个元素为R[n],直接交换R[1]与R[n],然后对前面无序区n-1个元素继续筛选(此时R[n]已经在有序区),把其变成最大堆之后再进行交换,直到进行n-1次所有元素归位

void sift(int R[], int low, int high)
{
	int i = low, j = 2 * i;
	int temp = R[i];
	while (j <= high)
	{
		if (j < high && R[j] < R[j + 1])
			j++;//选取R[i]更大的那个孩子结点
		if (temp < R[j])
		{
			R[i] = R[j];//把大于根节点的孩子结点上浮
			i = j;//把根节点下浮继续进行交换
			j = j * 2;
		}
		else
			break;//表示已经是最大堆了,不需要进行调整了
	}
	R[i] = temp;//把初始的根节点放到最后的根节点位置i上面,此时i也可能是最下面的叶子结点
}
void HeapSort(int R[], int n)
{
	int i;
	for (i = n / 2;i >= 1;i--)
		sift(R, i, n);//把初始堆变成最大堆
	for (i = n;i >= 2;i--)//进行n-1次归位与调整,得到有序序列
	{
		swap(R[i], R[1]);//把最大值放入无无序区最后的位置,此时这个位置变成有序区
		sift(R, 1, i - 1);//对交换后的无序区元素进行筛选
	}
}

8.归并排序,merge进行两两归并,mergepass把n/length条序列分别两两归并,得到n/(2*length)条序列;mergesort进行log2底n次mergepass,最终把序列不断两两归并成一条有序序列

void Merge(int R[], int low, int mid, int high)//简单的把两段有序序列合并成一段有序序列
{
	int* R1;
	int i = low, j = mid + 1, k = 0;
	R1 = new int[MaxSize];
	while (i <= mid && j <= high)//先把元素放入R1直到有一个序列放完为止
	{
		if (R[i] <= R[j])
		{
			R1[k] = R[i];
			i++;k++;
		}
		else
		{
			R1[k] = R[j];
			j++;k++;
		}
	}
	while (i <= mid)//表示第一段没有全部归并
	{
		R1[k] = R[i];
		i++;k++;
	}
	while (j <= high)//表示第二段没有完全归并
	{
		R1[k]= R[j];
		j++;k++;
	}
	for (k = 0, i = low;i <= high;k++, i++)
		R[i]= R1[k];
	delete []R1;
}
void MergePass(int R[], int length, int n)//把序列分成length长的若干段序列,然后分别两两归并
{
	int i;
	for (i = 0;i + 2 * length - 1 < n;i = i + 2 * length)
		Merge(R, i, i + length - 1, i + 2 * length - 1);
	if (i + length - 1 < n - 1)
		Merge(R, i, i + length - 1, n - 1);//收尾,把最后可能留下的序列归并
}//这里一开始有n/length段序列,经过归并后变成了n/(2*length)段有序序列
void MergeSort(int R[], int n)
{
	int length;
	for (length = 1;length < n;length = 2 * length)
		MergePass(R, length, n);//每一次执行,length变成原来的两倍,有序序列数量减半
	//直到length变成n/2,进行最后一次归并,得到最终的有序序列
	//这里进行log2底n次归并,每一次归并把n/length条有序序列变成n/(2*length)条
}

9.基数排序
假设数据为r进制,则设置r个链队,假设数据最大有d位,则进行d次分配收集这里是从最低位开始分配收集,直到把元素放入链队里面,然后再把链队从低到高连接起来组成新链这样进行d次分配收集之后,得到的链串里面的数据就是有序的

typedef struct node {
	char data[MaxSize];
	struct node* next;
}NodeType;
void RadisSort(NodeType*& p, int r, int d)//r代表基数,十进制则r=10,d为数据位数
{
	NodeType* head[MaxSize], * tail[MaxSize], * t;
	int i, j, k;
	for (i = 0;i < d - 1;i++)//从低位到高位循环,一般情况下i=0是个位,
	{
		for (j = 0;j < r;j++)//初始化各链队指针,基数为r所以需要r个链队
			head[j] = tail[j] = NULL;
		while (p != NULL)//对原来链表中各个结点元素放入相应的链队中
		{
			k = p->data[i] - '0';//此时是对第i位进行操作,找到每个元素第i位的数值,存在k中
			if (head[k] == NULL)
			{
				head[k] = p; // 并把链表对应的结点放入链队head[k]中
				tail[k] = p;
			}
			else
			{
				tail[k]->next = p;tail[k] = p;
			}
			p = p->next;//取下一个结点元素,直到所有元素放入对应的链队,完成了收集过程
		}
		p = NULL;//重新用p来收集所有结点
		for(j=0;j<r;j++)//一共有r条链队需要拼接在一起
			if (head[j] != NULL)//这个链队有结点
			{
				if (p == NULL)
				{
					p = head[j];t = tail[j];//把该链队赋给p
				}
				else
				{
					t->next = head[j];t = tail[j];//把链队连接在p链上
				}
			}
		t->next = NULL;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值