排序项:作为排序依据的数据称为排序项,也称为记录的关键码(Keyword)
* 主关键码 (Primary Keyword) 如果关键码是主关键码 排序结果是唯一的
* 次关键码(Secondary Keyword) 如果关键码是次关键码 则排序结果不唯一
如果使用某个排序方法对任意的记录序列按关键码进行排序,相同的关键码值的记录之间的位置关系与排列前一致,则排序方法是稳定的;如果不一致,则排序方法是不稳定的。
主关键码就是 姓名的ASCALL码值,次关键码就是 分数
如果一个排序方法以次关键码(分数)进行从大到小排序,如果每一次排序结果的 a,b前后位置都没有发生改变,那么这个方式就是稳定方法,但是如果有一次a,b位置发生改变,那么这个方法就是不稳定方法,
四种排序算法
这里我画了一个图有点抽象,看文字,辅助理解
排序思路:从第二个元素开始遍历,让当前的元素(a)和前面的所有的元素(b)进行比较,如果前面的元素(b)大于当前元素(a)就把(b)向后移动一位下标,如果前面的元素(b)小于当前元素(a),那么就把当前元素(a)存储(b)下标+1的位置。遍历完后如果所有的(b)都大于当前元素(a)那么就把(a)存入第一个元素的位置。
代码
///
/// 直接插入算法 稳定排序
///
///
static void InsetSort(int[] array)
{
//首先从第二个元素开始遍历
for (int i = 1; i < array.Length; i++)
{
int value = array[i];
bool isMin = true;
//让 i 下标前的全部数据和 i下标数据进行比较
for (int j = i-1; j>=0 ; j--)
{
if(array[j]>value)//只要比i下标数据大就向后移一位下标,
{
array[j + 1] = array[j];
}
else//如果比i下标数据小或者相等,那么就把i下标数据赋值到他后面
{
array[j+1] = value;
isMin = false;
break;//这里需要跳出循环,因为前面的值都是比i下标数据小
}
}
if(isMin)//如果遍历完了,前面的数据都比我大,那i下标数据就到第一个位置去
{
array[0] = value;
}
}
}
排序思路:这个比较好理解,就是拿第一个元素和后面所有的元素进行比较,找出最小的然后交换位置,再拿第二元素和后面全
的元素进行比较,然后交换位置,一直遍历到长度-2个元素。
代码
///
/// 简单选择排序 不稳定排序
///
///
static void SelectSort(int[] array)
{
for (int j = 0; j < array.Length-1; j++)//遍历次数长度-1
{
int index = j;
for (int i = j + 1; i < array.Length; i++)
{
if (array[i] < array[index])//找到最小的
{
index = i;
}
}
//交换位置
int temp = array[index];
array[index] = array[j];
array[j] = temp;
}
}
排序思路:冒泡排序的思路就是,让相邻的两数据进行比较,满足条件就进行位置交换,这样一轮遍历下来,最后一个数据一定是最大或者最小的,这样下一轮遍历就可以不用遍历最后一个数据,以此类推,遍历次数是数组长度-1
代码
///
/// 冒泡排序 稳定排序
///
///
static void BubbleSort(int[] array)
{
for (int i = 1; i < array.Length ; i++)//遍历数组长度-1的次
{
for (int j = 0; j < array.Length - i; j++)
{
if (array[j] > array[j + 1])
{
//位置交换
int temp = array[j + 1];
array[j + 1] = array[j];
array[j] = temp;
}
}
}
}
这里放一张维基百科上快速排序的GIF图,一看就知道咋回事
排序思路:快速排序采用了一个分治的策略,在开始排序前,你需要先获得三个参数,i=0(i代表第一位索引);j=7(j代表最后一个位索引),x=[i]=89(x代表第一位索引的值)。拿到参数后,x 的作用是保存的 i 位置的元素,所以现在 i 位置等于是空出来了,于是我们开始操作,我们先从 j 开始向前遍历,如果发现比 x 大 那么 j–,如果发现比x小的数就把他存入 i 的位置,这时 j 的位置就空出来,我们在从 i 开始遍历,如果发现比 x 小,那么 i++,如果发比 x 大的数,就把他存入 j 的位置,此时 i 的位置就又空出来了,就这样一直循环直到 j==i 或者 j !> i 。就停止循环,然后我们在把 x 赋值到 i 或者 j 位置 。这样第一轮就做完了,我们等于是以 x=[i]=89 为中间值 把大于他的数放到了他的右边,小于他的数放到了左边。
第一轮完成后的数组的排序,你会发现,i=4左边的数都是小于89的,右边的数都是大于89的,但是这两边的数据排序确实不对的,所以这个时候我们就需要 递归调用,让89左边和右边的部分,再次调用一次本函数。
以上就是快速排序的思路,需要注意的事,快速排序的x可以是数组里面随便哪一个数,并不是固定的,这里用 i 索引的值是为了算法服务的。
代码
这是我自己写的
///
/// 快速排序 不稳定算法
///
///
/// 开始索引
/// 结束索引
static void QuickSort(int[] array,int left,int right)
{
if(left x)
{
array[j] = array[i];
break;
}
else//如果小于等于,那么就把i向后移
{
i++;
}
}
//这时已经跳出两个小循环了,说明i==j了,
//这是再把 x 赋值给i/j位置
array[i] = x;
}
//递归调用
QuickSort(array, left, i - 1);
QuickSort(array, j + 1, right);
}
}
这是维基百科上展示的快速排序的代码,他这里的 x 值用的就不是 i 索引的值,而是中间索引的值
///
/// 快速排序2
///
///
///
///
static void QuickSortPlus(int[] numbers, int left, int right)
{
if (left < right)
{
//因为他拿到的是中间索引的值,所以不需要随后一步赋值
int middle = numbers[(left + right) / 2];
int i = left - 1;
int j = right + 1;
while (true)
{
while (numbers[++i] < middle) ;
while (numbers[--j] > middle) ;
if (i >= j)
break;
Swap(numbers, i, j);
}
QuickSortPlus(numbers, left, i - 1);
QuickSortPlus(numbers, j + 1, right);
}
}
//数据交换方法
static void Swap(int[] numbers, int i, int j)
{
int number = numbers[i];
numbers[i] = numbers[j];
numbers[j] = number;
}
测试
这里我做了一个测试,给1000个数排序,看那种方法耗时最短。
static void Main(string[] args)
{
//排序算法测试
int[] intArray = new int[] { 5, 16, 100, 1, 3, 50, 250, 23, 40, 21, 4, 15 };
int[] arrays = new int[1000];
//写入数据
for (int i = 0; i <1000; i++)
{
arrays[i] = intArray[i % 10];
}
//打印
foreach (int t in arrays)
{
Console.Write(t + " ");
}
Console.WriteLine();
//开始排序
DateTime beforSave = System.DateTime.Now;
//InsetSort(arrays);
//SelectSort(arrays);
//BubbleSort(arrays);
//QuickSort(arrays, 0, arrays.Length - 1);
//QuickSortPlus(arrays, 0, arrays.Length - 1);
DateTime afterSave = System.DateTime.Now;
TimeSpan cost = afterSave.Subtract(beforSave);
Console.WriteLine("排序花费时间 " + cost);
Console.WriteLine();
//打印结果
foreach (int t in arrays)
{
Console.Write(t + " ");
}
Console.ReadKey();
}
测试结果
1.直接插入排序
2.简单选择排序
3.冒泡排序
4.快速排序(自己的版本)
4.1快速排序(维基百科的版本)
上面的测试,可以自己试一下,不知到是不是1000个数太少了,多次的测试,结果出入还是比较大的
分享让知识变得有意义!后续会继续更新一些学习中问题。
OJMars
InTheMars