排序算法

排序:将一连串记录按照关键字的大小(从大到小或从小到大)进行排列。

稳定性:如果两个大小相同的关键字的相对位置在排序前和排序后是一样的(Ai等于Aj,排序前Ai 在Aj的前面,排序后Ai 还是在Aj的前面),那么这种算法就是稳定的。

稳定的排序算法有:冒泡排序、直接插入排序、归并排序、基数排序

不稳定的排序算法有:选择排序、快速排序、希尔排序、堆排序


冒泡排序:

        每轮都是从第一个元素开始,按顺序比较相邻的2个元素,将大的元素放到后面,小的元素放到前面。这样经过第一轮后,最大的元素位于最后的位置。第二轮后第二大的元素将位于倒数第2的位置。经过N-1轮后,所有的元素都将按从小到大排列。

        最好的时间复杂度为O(n),最坏的时间复杂度为O(n^2),平均时间复杂度为O(n^2)。

c++代码:

void BubbleSort(int iArr[], int iNum)
{
	int i, j, iTemp;
	for (i = 0; i < iNum - 1; i++) //总共进行iNum-1轮
	{
		for (j = 0; j < iNum - i - 1; j++) //每轮要比较的次数为iNum-i-1
		{
			if (iArr[j] > iArr[j + 1]) //将大的元素往后放
			{
				iTemp = iArr[j];
				iArr[j] = iArr[j + 1];
				iArr[j + 1] = iTemp;
			}
		}
	}
}


直接插入排序:

        每次从无序表中取出第一个元素,把它插入到有序表的适合位置,使有序表仍然有序。

        平均时间复杂度为O(n^2)。

c++代码:

void InsertionSort(int iArr[], int iNum)
{
	int i, j, iTemp;
	for (i = 1; i < iNum; i++) //总共进行iNum-1轮
	{
		iTemp = iArr[i]; //将当前要插入的元素先备份
		j = i - 1; //从要插入元素的前一个元素开始比较
		while((j >= 0) && (iArr[j] > iTemp)) 
		{
		        //将比iTemp大的元素往后移一个位置
			iArr[j + 1] = iArr[j];
			j--;
		}
		//如果j不等于i-1,说明这一轮有元素移动
		if (j != i - 1)
		{
			iArr[j + 1] = iTemp;//将要插入的元素放到适当的位置
		}
	}
}

归并排序:

        假设有一个数列{2,0,1,6,3,8,7,4,5,9}

        第一次归并后:{0,2},{1,6},{3,8}{4,7},{5,9}

        第二次归并后:{0,1,2,6},{3,4,7,8},{5,9}

        第三次归并后:{0,1,2,3,4,6,7,8},{5,9}

        第四次归并后:{0,1,2,3,4,5,6,7,8,9}

        平均时间复杂度为O(nlogn)。

基数排序:

        先将元素按个位数大小进行排序,再将元素按十位数大小进行排序····

        假设有一数列{73,22,93,43,55,14,28,65,39,81}

        按个位数排序后:{81,22,73,93,43,14,55,65,28,39}

        按十位数排序后:{14,22,28,39,43,55,65,73,81,93}

        平均时间复杂度为O(n)。

c++代码:

void RadixSort(int iArr[], int iNum)
{

	int iMax = iArr[0];
	for (int i = 1; i < iNum; i++)//获取序列的最大元素
	{
		if (iMax < iArr[i])
			iMax = iArr[i];
	}

	int iLoop = 0;
	while (iMax != 0)//计算最大元素的位数
	{
		iLoop++;
		iMax /= 10;
	}

	int iRow;
	for (int i = 1; i <= iLoop; i++)//根据最大位数进行循环
	{
		//iBackup的第一列用来存放对应行中存放的元素个数
		int iBackup[10][20] = {0};
		int iNumber = pow(10.0, i - 1);
		
		for (int j = 0; j < iNum; j++)//遍历所有元素
		{
			//第一轮计算个位数,第二轮计算十位数•••
			iRow = (iArr[j] / iNumber) % 10;
			
			//将元素按照iRow的大小存放到iBackup对应的行中
			int ilist = ++iBackup[iRow][0];
			iBackup[iRow][ilist] = iArr[j];

		}

		int k = 0;
		//按顺序将iBackup中的元素放回iArr数组中
		for (int m = 0; m < 10; m++)
		{
			for (int n = 1; n <= iBackup[m][0]; n++)
			{
				iArr[k++] = iBackup[m][n];
			}
		}
	}
}

选择排序:

        每一次从待排序的元素中选出最小的一个元素,放在序列的起始位置。

        平均时间复杂度为O(n^2)。

c++代码:

void SelectSort(int iArr[], int iNum)
{

	for (int i = 0; i < iNum - 1; i++) //总共进行iNum-1轮
	{
		int iMin = i;//iMin为本轮中最小元素的下标
		for (int j = i + 1; j < iNum; j++)//查找本轮最小元素
		{
			if (iArr[iMin] > iArr[j])
			{
				iMin = j;
			}
		}

		if (iMin != i)
		{
			//将本轮最小元素放在序列开头
			int iSwap = iArr[i];
			iArr[i] = iArr[iMin];
			iArr[iMin] = iSwap;
		}
	}
}

快速排序:

        通常选择序列的第一个元素为关键数据,将小于关键数据的元素放在关键数据前面,将大于关键数据的元素放在关键数据后面。然后再对关键数据前后两个序列做同样的递归操作。

        平均时间复杂度为O(nlogn)。

c++代码:

void QuickSort(int iArr[], int iLeft, int iRight)
{
	int i = iLeft;
	int j = iRight;
	int iKey = iArr[i];//将当前区间的第一个元素作为关键数据

	if (iLeft >= iRight)
		return ;//不能再划分,直接返回

	while(i < j)
	{
		//将比iKey小的元素往前放
		while(i < j && iArr[j] >= iKey)
		{
			j--;
		}
		iArr[i] = iArr[j];
		
		//将比iKey大的元素往后放
		while(i < j && iArr[i] <= iKey)
		{
			i++;
		}
		iArr[j] = iArr[i];
	}

	iArr[i] = iKey;//将iKey放中间
	QuickSort(iArr, iLeft, i - 1);//继续递归操作
	QuickSort(iArr, i + 1, iRight);
}

希尔排序:

        希尔排序是插入排序的一种。它是把元素按照下标的一定增量分组,再对每组使用直接插入排序。随着增量逐渐减少,每组包含的元素越来越多。当增量减少到1时,所有的元素正好分成1组。

        平均时间复杂度为O(n^1.25。

c++代码:

void ShellSort(int iArr[], int iNum)
{
	int i, j, iGap, k;
	for (iGap = iNum / 2; iGap > 0; iGap /= 2)//增量
	{
		for (i = 0; i < iGap; i++)//遍历每个分组
		{
			for (j = i + iGap; j < iNum; j += iGap)//遍历每个分组中的元素
			{
				//对分组进行直接插入排序
				int iTemp = iArr[j];
				for (k = j - iGap; k >= 0 && iArr[k] > iTemp; k -= iGap)
				{
					iArr[k + iGap] = iArr[k];
				}
				iArr[k + iGap] = iTemp;
			}
		}
	}
}

堆排序:

        堆排序是利用了完全二叉树,它将元素列表组织成一个完全二叉树。第一轮操作过后,最大的元素将位于根节点,然后将根节点元素和最后一个节点元素对换。第二轮操作过后,第二大的元素将位于根节点(剩下N-1个元素中最大的元素),然后将根节点元素和倒数第二个节点元素对换。继续进行下去,直到整个二叉树是从小到大排列的。

        平均时间复杂度为O(nlogn)。

c++代码:

void HeapAdjust(int iArr[], int i, int iNum)
{
	//i是要调整的节点,执行该函数后以i为根节点的子树中,
	//i节点的值最大
	int iLchild = 2 * i + 1;
	int iRchild = 2 * i + 2;
	int iMax = i;

	if (i <= iNum / 2 - 1)
	{
		if (iLchild < iNum && iArr[iLchild] > iArr[iMax])
		{
			iMax = iLchild;
		}

		if (iRchild < iNum && iArr[iRchild] > iArr[iMax])
		{
			iMax = iRchild;
		}

		if (i != iMax)
		{
			int iTemp = iArr[i];
			iArr[i] = iArr[iMax];
			iArr[iMax] = iTemp;

			HeapAdjust(iArr, iMax, iNum);
		}
	}
}
//将数组组织成完全二叉树
void BuildHeap(int iArr[], int iNum)
{
	for (int i = iNum / 2 - 1; i >= 0; i--)
	{
		HeapAdjust(iArr, i, iNum);
	}
}
void HeapSort(int iArr[], int iNum)
{
	BuildHeap(iArr, iNum);
	for (int i = iNum - 1; i > 0; i--)
	{
		//将当前最大值与当前最后的节点对换
		int iTemp = iArr[0];
		iArr[0] = iArr[i];
		iArr[i] = iTemp;
		//对换后,重新调整
		HeapAdjust(iArr, 0, i);
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值