排序算法

排序算法的稳定性:

如有13, 2, 44, 56, 56*, 98, 10这个序列,

 稳定排序后:2, 10, 13, 44, 56, 56*, 98, 这可以做到两个相等的元素(复杂类型中为KEY)一定不互换

但不稳定排序后的结果可能是:2, 10, 13, 44, 56*, 56, 98, 这样并不能一定保证相等的两个元素的位置不互换,\

在基本类型中稳定或不稳定是无关紧要的,

但是在复杂类型中, 根据关键字排序, 使用不稳定排序, 可能会让两个相同关键字的元素交换位置, 这可能并不是开发者所设想的



冒泡排序:

void BubleSort(int arr[], int len)
{//冒泡排序, 最古老的排序, 效率最低的排序
    //思想 : 通过比较相临的元素, 如果前一个元素大于后一个元素, 就交换它们
    //这样每次就把当前比较中的元素, 最大的元素放到最后, 达到排序的目的
	for (int i = 0; i < len - 1; i++)
	{//外层循环次数为数组长度-1
		for (int j = 0; j < len - 1 - i; j++)
		{//内层循环每次递减, 因为最大的元素始终在最后, 没必要在比较最大的元素
			if (arr[j] > arr[j + 1])
			{//如果前一个比较大,则交换相临的两个元素
				int temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
	}
}


冒泡排序进阶版->快速排序

void QuickSort(int arr[], int left/*最左边元素下标*/, int right/*最右边元素下标*/)
{//快速排序
	//思想 : 采用分治算法, 找到一个关键字, 把小于关键字的元素放在关键字的左边
	//把大于关键字的放在关键字的右边,然后,递归,把左边的再次使用快排,右边的也
	//使用快排,最后完成排序
	if (left >= right)
	{//左下标和右下标重叠时, 返回
		return;
	}
	int i = left; //i从左往右表示下标
	int j = right + 1; //j从右往从表示下标, ***注 : 这里j要超尾,  j超尾, 但是right必需是最右边元素的下标***
	int varKey = arr[left]; //最左边的元素设定为关键字
	while (true)
	{//外层循环, 把关键字放到正确位置后, 退出循环
		do 
		{
			i++;
		} while (arr[i] < varKey);
		//从左往右找, 当找到比关键字小的, 退出
		do 
		{
			j--;
		} while (arr[j] > varKey); //从右往左找, 当找到比关键字, 退出
		if (i >= j) 
		{//当i与j重叠时,退出外层循环
			break;
		}
		//相换两个元素
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	arr[left] = arr[j];
	arr[j] = varKey; //最后把关键字放到左组和右组的中间, 同时也以经确定了关键字的正确位置
	QuickSort(arr, left, j - 1); //把关键字左边的组进行快排
	QuickSort(arr, j + 1, right); //所关键字右边的组进行快排
}



直接插入排序

void InsertionSort(int arr[], int len)
{//直接插入排序
	//思想 : 首先让外层的当前元素为待排序元素(temp), 
	//然后和有序列表中以从后往前的顺序进行比较
	//最后将待排序元素插入到以经排好序的列表中
	//一开始有序列表长度为1, 然后为2....直到最后长度为整个数组的长度
	for (int i = 1; i < len; i++)
	{//外层循环为数组长度, 这里从第二个元素开始插入, 因为一个元素不存在排序
		int temp = arr[i]; //设置待排序元素
		int j = i - 1; 
		while (j >= 0 && arr[j] > temp)
		{//当j>0时, 并且待排元素小于当前比较元素, 则将当前元素后移, 然后继续同有序列表中前面的元素比较
			arr[j + 1] = arr[j];
			j--;
		}
		arr[j + 1] = temp;
	}
}


 直接插入排序进阶版->二分插入排序

void BinInsertionSort(int arr[], int len)
{//二分插入排序
	//思想 : 首先找到有序列表中中间的元素,
	//arr[mid] mid = (left(有序列表的第一个元素下标) + right(有序列表的最后一个元素下标)) / 2 
	//将待插入元素于中间元素比较, 如果待插元素较大, 则应插在中间元素右边, 则将left 标为mid的后面, 
	//再继续二分比较, 直到找到left的正确位置,然后将left元素后面的元素后移, 最后插入left
	int left/*有序表中第一个元素下标*/, right/*有序表中最后的元素下标*/, mid/*中间元素下标*/;
	for (int i = 1; i < len; i++)
	{//外层循环为数组长度, 这里从第二个元素开始插入, 因为一个元素不存在排序
		int temp = arr[i]; //取待插入元素
		left = 0; 
		right = i - 1;
		while (left <= right)
		{//确定left下标的循环, 不停的将当前段截成左右两段
			mid = (left + right) / 2; //mid为当前段的中间元素下标
			if (temp < arr[mid])
			{//如果待插元素比中间元素小, 将left 到 right段设置为原先mid段的左边
				right = mid - 1;
			}
			else
			{//否则, 将left到right段设置为原先mid段的右边
				left = mid	+ 1;
			}
		}
		for (int j = i - 1; j >= left; j--)
		{//将有序列表中left下标后的元素后移, 这里操作的就是整个有序列表了.
			arr[j + 1] = arr[j];
		}
		arr[left] = temp; //插入待排序元素
	}
}


直接插入排序终级版->希尔排序:

设置一个步长,然后将在步长内的元素分组, 然后在分组内进行直接插入排序

void ShellSort(int arr[], int len)
{//希尔排序
	//恩想 : 设定一个步长, 然后将相隔该步长的元素分到一组,
	//进行比较,符合条件就交换,然后继续与该组前面的元素进行比较, 
	//不符合条件就停止该组的比较
	int d; //步长, 不断减半, 直到为1
	int j; 
	for (d = len / 2; d >= 1; d = d / 2)
	{//外层为步长/2直到为1的循环次数
		for (int i = d; i < len; i++)
		{//将i设置为当前步长, 并定为元素下标
			int temp = arr[i]; //设置待插入元素, 注意是从后入前的顺序比较, 待插入元素为该步长最后元素
			for (j = i - d; (j >= 0) && (arr[j] > temp); j = j - d)
			{//设置当前比较元素, 当该组中前面的元素比较大时, 把较小元素插到该分组的前面
				arr[j + d] = arr[j]; //后移的位置为步长
			}
			arr[j + d] = temp;
		}
	}
}


选择排序:

void SelectionSort(int arr[], int len)
{//选择排序
	//每次选出最小的元素与数组最前端的元素进行排序
	int min = 0; //最小元素的下标
	for (int i = 0; i < len - 1; i++)
	{//外层循环为数组长度-1
		min = i; //min为当前元素下标
		for (int j = i + 1; j < len ; j++)
		{//内层循环只在没有被选为最小元素的元素中进行选择
			if (arr[j] < arr[min])
			{//当前元素比"临时最小元素"小, 获得该较小元素下标
				min = j;
			}
		}
		if (min != i)
		{//把当前元素(arr[i])与arr[min]互换, 因为这时的i肯定是在数组的前最前端元素
			int temp = arr[min];
			arr[min] = arr[i];
			arr[i] = temp;
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值