八股文之八大排序(C++)

14 篇文章 0 订阅
3 篇文章 0 订阅

目录

1.直接插入排序

2.希尔排序

3.简单选择排序

4.堆排序

5.冒泡排序

6.快速排序

7.归并排序

8.基数排序(桶排序)

9.主函数

10.画图总结


1.直接插入排序

int ai[] 为需要排序的数组

start 为起始位置,要求 start>=1 ,因为 ai[0] 要作为“哨兵”使用。

end 为结束位置

代码思路:看后面的数字有没有比前面的大,比前面的大则需要插入交换,从后往前,依次比较,依次往后移一位,直到不满足

void InsertSort(vector<int>&arr, int len)
{
	int tmp = 0;
	for (int i = 1; i < len; i++)//第一张扑克牌无需比较
	{
		tmp = arr[i];
		if (arr[i] < arr[i - 1])//满足需要交换的条件
		{
			for (int j = i - 1; j >= 0&&arr[j]>tmp; j--)//这里多加了一个判断,因为之前if语句进入之后,第一次循环没有问题,但当第二次及之后的循环开始,没有这个判断,代码会直接交换,不在乎大小
			{
				arr[j+1] = arr[j];
				arr[j] = tmp;
			}
		}
	}
}

2.希尔排序

希尔排序:进阶版的直接插入排序

  • 原理:将一组数进行分组,比如按5 3 1分组,就是开始五个数为一组,再3个数,最后一个数,分组后,每一组的第一个相互比较,观察满不满足交换条件,依次第二个、第三个,直到这个分组的数比较完成,再开始下一个分组

  • 算法的优点在于它首先保证局部的大致有序,让最后的直接插入排序交换的次数减少

void ShellSort(vector<int>& arr, int len)
{
    int inc = 0, i = 0, j = 0, tmp = 0;
  //inc是初始增量,每次除2
   for (inc = len / 2; inc >0; inc /= 2)
   {
	//插入排序
	   for (i = inc; i < len; i++)
	   {
		   tmp = arr[i];
		   for (j = i; j >= inc&&tmp<arr[j-inc]; j-=inc)
		  {
			  arr[j] = arr[j-inc];
		   }
           arr[j] = tmp;
	   }
    }
}

3.简单选择排序

简单选择排序:一直寻找剩余数组中最小的元素放到前面

void SelectSort(vector<int>& arr, int len)
{
	int tmp = 0;
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = i + 1; j < len; j++)
		{
			if (arr[i] > arr[j])//因为这里一直是和i所在位置的元素比,所以不是像冒泡排序一样全部用j
			{
				tmp = arr[j];
				arr[j] = arr[i];
				arr[i] = tmp;
			}
		}
	}
}

4.堆排序

  • 堆排序:堆调整+堆排序

  • 将最开始的数组构建完全二叉树,通过堆调整让最大的数出现在根节点上,交换根节点与最后一个节点,将除最后一个节点的其他数再次调整,最大的数位于根节点,以此类推

void Adjust(vector<int>& arr, int len, int index)
{
	int left = 2 * index + 1;//左孩子
	int right = 2 * index + 2;//右孩子
	int maxIdx = index;
	if (left<len && arr[left]>arr[maxIdx])maxIdx = left;
	if (right<len && arr[right]>arr[maxIdx])maxIdx = right;//经过两个if判断后,maxIdx是父节点以及两个叶子节点之中最大值的下标

	if (maxIdx != index)//maxIdx如果发生变化
	{
		swap(arr[maxIdx], arr[index]);//交换下标对应的值,让最大值处于根节点
		Adjust(arr, len, maxIdx);//继续调整
	}
}
void HeapSort(vector<int>&arr,int len)
{
	for (int i = len / 2 - 1; i >= 0; i--)
	{
		Adjust(arr, len, i);//从最下层的非叶子节点开始调整

	}
	for (int i = len - 1; i >= 1; i--)//这里i不取0是因为剩余一个数的时候不用交换
	{
		swap(arr[0], arr[i]);//根节点的数与结尾的数进行交换,再次循环去调整
		Adjust(arr, i, 0);//寻找最大的数放到根节点,重复以上步骤

	}
}

5.冒泡排序

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

void BubbleSort(vector<int>& ai, int len)
{
	int i = 0, j = 0,tmp=0;
	for (i=0; i < len-1; ++i)//比如10个数只用9趟排序就可以
	{
		for (j=0;j < len -1-i; j++)
		{
			if (ai[j] > ai[j + 1])
			{
				 tmp = ai[j];
				ai[j] = ai[j + 1];
				ai[j + 1] = tmp;
			}
		}
	}
}

6.快速排序

划分函数+递归调用

  • 以第一个数为基准,将所有数按照基准划分左右,左边小,右边大,对左子序列和右子序列重复以上操作

 int Part(vector<int>& arr, int low, int high)
{
	int pivot = arr[low];//一般以第一个数为基准
	int i = low, j = high;
	while (i < j)
	{
		while (i < j && arr[j] > pivot)
		{
			j--;
		}
		if (i < j)//走到这说明上个while循环的第二个条件是不满足的
		{
			swap(arr[i], arr[j]);
			i++;
		}
		while (i < j && arr[i] <= pivot)
		{
			i++;
		}
		if (i < j)
		{
			swap(arr[i], arr[j]);
			j--;
		}
	}
	return i;//返回最后基准划分所在的下标
}
void QuickSort(vector<int>& arr, int left, int right)
{
	int mid = 0;
	if (left < right)
	{
		mid = Part(arr, left, right);
		QuickSort(arr, left, mid - 1);//等到这里失败才会进行下面的递归,所以 这里失败的时候就是已经有序的情况
		QuickSort(arr, mid + 1, right);
	}
}

7.归并排序

归并排序:将数组进行分组,保证组内有序,分成最小的组也就是一个数组一组,因为默认一个数字就是有序,所以开始两两一组排序,有序的合并两两一组就变成了四个数一组,依次递增,直到最后合并为一组

void Merge(vector<int>& arr,int *temp, int left, int mid, int right)
{
	
	int k = left, i = left, j = mid + 1;
	while (i != mid+1 && j <= right)
	{
		if (arr[i] <= arr[j])temp[k++] = arr[i++];
		else
		{
			temp[k++] = arr[j++];
		}

	}
	while (i <= mid)
	{
		temp[k++] = arr[i++];//右边数据已经放完,将左边已经有序的数据放入temp中
	}
	while (j <= right)
	{
		temp[k++] = arr[j++];//左边数据已经放完
	}

	for (int i= 0;i< k ; i++)
	{
		arr[i] = temp[i];
	}
	
}
void MergeSort(vector<int>& arr,int *temp, int left, int right)
{
	if (left == right)
	{
		return;
	}
	else
	{
		int mid = left + (right-left) / 2;
		MergeSort(arr, temp,left, mid);
		MergeSort(arr,temp, mid + 1, right);
		Merge(arr,temp,left, mid, right);
	}
}

8.基数排序(桶排序)

以最大的数的位数为标准,比如最大数是255,最高位是百位,那么就进行三次排列,将每个数的个位放入对应的桶,桶从0-9,比如277,第一步个位为7,所以放入下标为7的桶中,依次放入所有的数,由于可能有多个数的个位相同,所以这个桶是一个二维数组;最后把二维数组里的数又放回原始数组里,完成第一趟排序,但这样存在一个问题就是有些桶可能没有数据,不需要遍历,所以增加一个数组bucketIndex来记录每个桶内放入多少数据;遍历的时候加上这个限制,最后,把下标桶(bucketIndex)中的数据清零,至此,完成了第一次排序。

void RadixSort(vector<int>& arr, int len)
{
	//1.找出最大值
	int max = arr[0];
	int bucket[10][1000];//这里必须给常量值,这个二维数组是存放数据的数组
	int bucketIndex[] = { 0,0,0,0,0,0,0,0,0,0 };//记录0-9这些桶里是否有数据
	for (int i = 1; i < len; i++)
	{
		max = arr[i] > max ? arr[i] : max;
	}
	int divisor = 1;//控制最大数获取各个位的数,比如获取个位除1然后%10就可,获取十位就是除以10然后%10
	//2.循环找出最大值的位数
	while (max > 0)
	{
       //遍历数组放入桶中
		for (int i = 0; i < len; i++)
		{
			int temp = arr[i]/divisor%10;//依次求出这个数的个位十位等
			bucket[temp][bucketIndex[temp]] = arr[i];
			bucketIndex[temp]++;//计数加加

		}
		//3.把桶中的数据重新赋值给原始数组
		int index = 0;
		for (int i = 0; i < 10; i++)
		{
			if (bucketIndex[i] != 0)//代表有数据
			{
				for (int j = 0; j < bucketIndex[i]; j++)
				{
					arr[index++] = bucket[i][j];
				}
			}
		}
		//4.清空下标桶
		for (int i = 0; i < 10; i++)
		{
			bucketIndex[i] = 0;
		}

		divisor *= 10;
		max /= 10;
	}

}

9.主函数

void main()
{
	int ar[] = { 8, 1,200, 14, 3, 21, 5, 7, 10 ,0};
	int len = sizeof(ar) / sizeof(ar[0]);
	vector<int>arr(ar, ar +len);
	int* brr = new int[len];
	
	BubbleSort(arr, len);//冒泡排序
	cout << "冒泡排序:      ";
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << "    ";
	}
	cout << endl;
	InsertSort(arr, len);//直接插入
	cout << "直接插入排序:  ";
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << "    ";
	}
	cout << endl;
	ShellSort(arr, len);//希尔排序
	cout << "希尔排序:      ";
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << "    ";
	}
	cout << endl;
	SelectSort(arr, len);//简单选择排序
	cout << "简单选择排序:  ";
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << "    ";
	}
	cout << endl;
	HeapSort(arr, len);//堆排序
	cout << "堆排序:        ";
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << "    ";
	}
	cout << endl;
	QuickSort(arr, 0, len - 1);//快速排序
	cout << "快速排序:      ";
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << "    ";
	}
	cout << endl;
	MergeSort(arr,brr, 0, len-1);//归并排序
	cout << "归并排序:      ";
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << "    ";
	}
	cout << endl;
	RadixSort(arr, len);//基数(桶)排序
	cout << "基数(桶)排序:";
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << "    ";
	}
	cout << endl;
	delete[]brr;
	brr = nullptr;
}

截图:

 

10.画图总结

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我在凌晨等太阳¤

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值