排序算法小结
最近没有工作,闲来无事看看算法,从排序算法开始
- 选择排序
- 冒泡排序法
- 快速排序法
- 插入排序
- 直接选择排序法
- 堆排序
- 其它排序
- 直接插入排序法
- 希尔排序法
- 归并排序法
冒泡排序
将数组遍历,第一个数与第二个数比较,把较小的数拿出来,再与第三个数比较,把最小的数拿出来,循环一次,把最小的数拿出来了,第二次循环的次数会减少一次,找到第二小的数,最后排序完成。
//核心代码
//缓存元素
Integer temp;
for (int i = 0; i < beforeNum.length - 1; i++) {
for (int j = beforeNum.length - 1; j > i; j--)
if (beforeNum[j - 1] > beforeNum[j]) {
temp = beforeNum[j];
beforeNum[j] = beforeNum[j - 1];
beforeNum[j - 1] = temp;
}
}
快速排序
设定一个初始值s,两个指针i,j分别指向第一个位置与最后一个位置,j从后往前找比s小的数,i从前往后找比s大的数,找到之后,i,j数进行交换,继续,直到ij相遇,将base与i进行交换。自此,左右的数分别比s小或者大,再分别对左右进行排序,可得。
程序实现:1.找到基准值,2.对基准值进行排序(递归调用)
//快速排序法 ----选定一个初始值s,2个哨兵i(开始位置)j(结束位置)i从前往后遍历,j从后往前遍历(先)
//j找比s小的数,i找比s大的数,交换,如果ij相遇,s与i交换。此时,s左边的数比s小,s右边的数比s大
//对左边与右边的数分别再进行操作
public static int division(int[] list, int left, int right) {
//选择一个基准元素值s
int baseNum = list[left];
while (left < right) {
//从数组右端开始找,找比baseNum小的数
while (left < right && list[right] >= baseNum)
right--;
//将j赋值给基准值
list[left] = list[right];
//从数组左端开始,找比基准值大的数
while (left < right && list[left] <= baseNum)
left++;
//将left值赋给右边
list[right] = list[left];
}
list[left] = baseNum;
return left;
}
//快速排序
public static int[] quickSort(int[] startNum, int left, int right) {
if (left < right) {
//分割数据
int i = division(startNum, left, right);
quickSort(startNum, left, i - 1);
quickSort(startNum, i + 1, right);
}
return startNum;
}
直接选择排序
选定一个初始值,将初始值与后面所有数进行比较,找到最小值,交换,在除最小值的数里面找最小值,放到第二位,以此类推。程序实现思路是遍历数组,找到下标最小值,进行数据交换。
for (int i = 0; i < list.length - 1; i++) {
//假设下标值最小
int tempIndex = i;
for (int j = i + 1; j < list.length - 1; j++) {
if (list[tempIndex] > list[j]) {
tempIndex = j;
}
}
//数据交换
int temData = list[tempIndex];
list[tempIndex] = list[i];
list[i] = temData;
}
堆排序
堆排序需要用到二叉树构建大根堆(父节点比左右孩子都要大),
从根结点3开始,不用交换,左结点2与5交换,交换后再将5与3交换,交换后再将3与4交换,请自行脑补。。。。 每次构建后会对二叉树进行破坏,所以需要重新构建。
//堆排序
//调整堆方法
public static void heapAdjust(int[] list, int parent, int length) {
//temp保存当前父节点
int temp = list[parent];
//得到左孩子(这可是二叉树的定义,大家看图也可知道)
int child = 2 * parent + 1;
while (child < length) {
//如果parent有右孩子,则要判断左孩子是否小于右孩子
if (child + 1 < length && list[child] < list[child + 1])
child++;
//父亲节点大于子节点,就不用做交换
if (temp >= list[child])
break;
//将较大子节点的值赋给父亲节点
list[parent] = list[child];
//然后将子节点做为父亲节点,已防止是否破坏根堆时重新构造
parent = child;
//找到该父亲节点较小的左孩子节点
child = 2 * parent + 1;
}
//最后将temp值赋给较大的子节点,以形成两值交换
list[parent] = temp;
}
//堆排序算法
public static int[] heapSort(int[] list) {
//list.Count/2-1:就是堆中父节点的个数
for (int i = list.length / 2 - 1; i >= 0; i--) {
heapAdjust(list, i, list.length);
}
//最后输出堆元素
for (int i = list.length - 1; i > 0; i--) {
//堆顶与当前堆的第i个元素进行值对调
int temp = list[0];
list[0] = list[i];
list[i] = temp;
//因为两值交换,可能破坏根堆,所以必须重新构造
heapAdjust(list, 0, i);
}
return list;
}
直接插入法排序(类似玩牌后理牌)
从无序数列中取出一个数,再取出一个数,对比插入到有序数列前面或者后面,每次取出一个数,进行插入。
//无序序列
for (int i = 1; i < list.length; i++) {
int temp = list[i];
int j;
for (j = i - 1; j < i && temp < list[j]; j--) {
list[j + 1] = list[j];
}
list[j + 1] = temp;
}
希尔排序是对插入排序的补充
归并排序,将所有的数进行拆分到原子级别,再对原子级别的数亮亮合并。
ps:由于自身实力的限制,后面几种排序有的没有写例子,感觉不怎么好理解,只能后面再来研究了。可以查看我的参考博客,感觉这个大哥写的东西很好,推荐。另附上我的代码地址(有很多不足还请指教)。https://gitee.com/zhoujie1/studyTest.git
参考博客
1.https://www.cnblogs.com/huangxincheng/archive/2011/11/14/2249046.html
2.https://www.cnblogs.com/huangxincheng/archive/2011/11/16/2251196.html
3.https://www.cnblogs.com/huangxincheng/archive/2011/11/20/2255695.html