Java基础复习笔记基本排序算法

1. 排序

排序是一个历来都是很多算法家热衷的领域,到现在还有很多数学家兼计算机专家还在研究。而排序是计算机程序开发中常用的一种操作。为何需要排序呢。我们在所有的系统中几乎都要检索数据,而这些欲检索的数据如果有规律的话,比如按照某些字段、属性降序排序的话,那么从这些有规律的数据查询结果或者结果集的话就快速得多。

2. 常用算法

常用的算法有:直接选择排序、堆排序、冒泡排序、快速交换排序、直接插入排序、折半插入排序、Shell排序、归并排序、桶式排序、基数排序。这些都属于常用排序算法,也都是内部排序算法。所谓内部排序就是不借助任何外部的内存处理器,直接使用内存,在内存中完成就可以的排序方式。

3. 直接选择排序

直接排序的思想就是进行二重遍历,由外层元素依次和内层元素进行对比,之后交换位置。算法如下

package sort;
import java.util.Arrays;
/**
* 选择排序
*/
public class SelectSort {
// 选择排序法
public static void selectSort(Integer[] integers) {
for (int i = 0; i < integers.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < integers.length; j++) {
if (integers[i] < integers[j]
&& integers[minIndex] < integers[j]) {
// 只记住标记
minIndex = j;
}
}
// 每次只交换一次即可
if (minIndex != i) {
Integer temp = integers[i];
integers[i] = integers[minIndex];
integers[minIndex] = temp;
}
}
}
}

4. 堆排序

堆排序的思想就是将要排序的数组看成一个完全二叉树(出最后一层节点外,其他节点都是2个子节点),之后建立大顶堆,将完全二叉树建立成一个父节点值都大于它的子节点的树。之后将根节点和要排序的数组的最后一个元素进行换位。之后除了数组最后一个元素外重复建堆过程。算法如下

package sort;
import java.util.Arrays;
/**
* 堆排序
*/
public class HeapSort {
/**
* 构建堆数组
*/
public static void buildHeap(Integer[] datas, int lastIndex) {
//从目标的父节点开始遍历
for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
//记录父节点位置
int maxIndex = i; //当父节点的子节点存在的时候
while (maxIndex * 2 + 1 <= lastIndex) { //默认附一个大值为父节点的左子节点的索引
int biggerIndex = maxIndex * 2 + 1; //此处判断是否父节点还有一个右子节点
if (biggerIndex < lastIndex) {
//如果有右子节点判断左右子节点的值大小,记录一个最大的位置,好用于交换
if (datas[biggerIndex] < datas[biggerIndex + 1]) {
biggerIndex++;
}
} //此处是比较父节点值和左右子节点值,找个最大的做父亲
if (datas[maxIndex] < datas[biggerIndex]) {
Integer temp = datas[maxIndex];
datas[maxIndex] = datas[biggerIndex];
datas[biggerIndex] = temp; //记录一下最大值的索引
maxIndex = biggerIndex;
} else {
break;
}
}
}
}
/**
* 堆排序
*/
public static void heapSort(Integer[] datas) { // 数组大小
int arrayLength = datas.length; // 遍历数组
for (int i = 0; i < arrayLength - 1; i++) { // 构建堆
buildHeap(datas, arrayLength - 1 - i); // 交换元素
Integer temp = datas[0];
datas[0] = datas[arrayLength - 1 - i];
datas[arrayLength - 1 - i] = temp;
}
}

5. 冒泡排序

冒泡排序在使用频率上来说,也许是仅次于直接选择排序的算法的了。因为起泡的思想也很简单就是循环数组中的元素,相邻元素一一对比,进行交换。算法如下

package sort;
import java.util.Arrays;
/**
* 冒泡排序法
*/
public class BubbleSort {
/**
* 冒泡排序
*/
public static void bubbleSort(Integer[] datas) {
int datasLength = datas.length;
for (int i = 0; i < datasLength - 1; i++) {
for (int j = 0; j < datasLength - 1 - i; j++) {
if (datas[j] < datas[j + 1]) { // 交换之
Integer temp = datas[j + 1];
datas[j + 1] = datas[j];
datas[j] = temp;
}
}
}
}
}

6. 快速排序

所谓快速排序法是从待排序的数组中找一个标本作为分界值(一般是数组的第一个元素),所有比这个值小的值放到它的左边(或者右边),将比它大的值放到它的右边(或者左边),这样这个分界值左右两边的值要么全部比它大,要么全部比它小。之后再利用递归,将此标本右边、左边的所有元素也按部就班。算法如下

package sort;
import java.util.Arrays;
/**
* 快速排序
*/
public class QuickSort {
/**
* 交换数组元素位置
*/
public static void chang(Integer[] datas, int i, int j) {
Integer temp = datas[i];
datas[i] = datas[j];
datas[j] = temp;
}
/**
* 快速排序法
*/
public static void quickSort(Integer[] datas, int startIndex, int endIndex) { if (startIndex < endIndex) { //标本
Integer startData = datas[startIndex]; //左边的开始索引
int i = startIndex; //右边的开始索引
int j = endIndex + 1;
while (true) { //找左边比标本大的下标
while (i < endIndex && datas[++i] > startData){
} //找右边比标本小的下标
while (j > startIndex && datas[--j] < startData){
} if (i < j) {
//交换i、j元素位置
chang(datas, i, j);
} else {
break;
}
} //交换开始位置、j的元素为止
chang(datas, startIndex, j); //递归标本左边
quickSort(datas, startIndex, j - 1); //递归标本右边
quickSort(datas, j + 1, endIndex);
}
}
}

7. 直接插入排序

直接插入排序的原理就是将数组中的元素依次和前面元素进行比较,如果发现了比它大的(或者小的),记录标志位、记录被比较元素,之后从标志位一位一位的向后进行元素移动,之后空出来的的那一位就是留给被比较元素的。这样造成了一个现象就是被比较的元素前面的所有元素都是排序过了的。算法如下。

package sort;
import java.util.Arrays;
/**
* 直接插入排序
*/
public class InsertSort {
/**
* 直接插入
*/
public static void insertSort(Integer[] datas) { //从数组第二个元素开始遍历
for (int i = 1; i < datas.length; i++) { //当前元素和前一个元素进行对比【此处前面的元素已经排序好了】
if (datas[i] < datas[i - 1]) { //记录当前要比较的元素值
Integer temp = datas[i]; //从当前元素往前开始比较
int j = i - 1; //如果满足前面索引有效并且前面的元素值都是比当前值大的,那就进行元素后移动操作
for (; j >= 0 && datas[j] > temp; j--) { //元素后移
datas[j + 1] = datas[j]; } //前移操作后,j的索引就是中间那个比前面元素大,比后面元素小的位置索引-1
//将其要对比的值插进去
datas[j + 1] = temp;
}
}
}
}

8. 折半插入排序

折半插入排序是在原直接插入的基础上作了改进。对于折半插入法,被比较的元素不用和前面所有的元素进行一一对比,而是先找到0位元素到此被比较元素的中点元素,和这个重点元素进行比较,看看谁大,之后就是被比较元素元素和这个中点元素之间再找一个中点进行比较,或者是0点和原中点元素找个新中点。这样就可以缩小范围,反正排在被比较元素之前的元素是一个已经排好大小的序列,那就可以善加利用这已经排好的序列。当然了,找到位置后,该移动元素的还是要移动的。算法如下:

package sort;
import java.util.Arrays;
/**
* 折半排序
*/
public class BinaryInsertSort {
/**
* 折半排序
*/
public static void binaryInsertSort(Integer[] datas) { // 从数组第二个元素开始遍历
for (int i = 1; i < datas.length; i++) {
// 记录当前要比较的元素值
Integer temp = datas[i]; // 低位开始
int low = 0; // 高位开始
int hight = i - 1; // 位置有效,低位、高位
while (low <= hight) {
// 中间位置
int mind = (low + hight) / 2; //被比较元素大于中间元素
if (temp > datas[mind]) { //低位调整在中点之后
low = mind + 1;
} else {//被比较元素小于中间元素 //高位在中点之前
hight = mind - 1;
}
}
// 低高位调整完毕后,将中点元素依次往后移动
for (int j = i; j > low; j--) {
// 元素后移
datas[j] = datas[j - 1]; }
// 前移操作后,low的索引就是中间那个比前面元素大,比后面元素小的位置索引low
// 将其要对比的值插进去
datas[low] = temp;
}
}
}

9. 归并排序

归并排序的主要思想就是将原来的数组分开成2大部分,建立一个新的临时数组,分别从2部分开始顺序走,将2部分的元素进行比较,先将小元素放入到临时数组,之后索引往前走一位,剩下的在进行比较。算法如下:

package sort;
import java.util.Arrays;
/**
* 归并排序
*/
public class MergeSort {
/**
* 归并排序
*/
public static void mergeSort(Integer[] datas, int leftIndex, int rightIndex) { //当分块索引有效时
if (leftIndex < rightIndex) { //找出中间索引
int center = (leftIndex + rightIndex) / 2; //把左边到中点的元素集合继续分堆儿
mergeSort(datas, leftIndex, center); //把右边到中点的元素集合继续分堆儿
mergeSort(datas, center + 1, rightIndex); //归并
merge(datas, leftIndex, center, rightIndex);
}
}
/**
* 归并
*/
private static void merge(Integer[] datas, int left, int center, int right) { //建立一个临时的数组,用于装载排序后的数组
Integer[] temp = new Integer[datas.length]; //第二队的开始索引位置
int mind = center + 1; //临时数组从第一队的索引开始
int third = left; //仅仅记录开始索引位置
int tmp = left;
while (left <= center && mind <= right) {//分队后的数组进行比较
if (datas[left] <= datas[mind]) {
//左边的略小,左边索引前进
temp[third++] = datas[left++];
} else { //右边的略小,右边索引前进
temp[third++] = datas[mind++];
}
} //如果第二队数组还没走完,继续走完,将第二队右边的元素都放到临时数组后面
while (mind <= right) {
temp[third++] = datas[mind++];
} //如果第一队数组还没走完,继续走完,将第一队右边的元素都放到临时数组后面
while (left <= center) {
temp[third++] = datas[left++];
} //将临时数组中的所有元素(排序好的),原样覆盖到原先的数组
while (tmp <= right) {
datas[tmp] = temp[tmp++];
}
}
}

总结到这里发现自己实在不行了。要吐了,算法真的是数学大师+计算机专业的人才能搞得了得。相当于大脑就是一个编译器+数学公式器+内存监视器。向所有世界上还在为算法而奋斗的人们,先总结到这里。

Java基础复习笔记基本排序算法的更多相关文章

  1. Java基础复习笔记系列 四 数组

    Java基础复习笔记系列之 数组 1.数组初步介绍? Java中的数组是引用类型,不可以直接分配在栈上.不同于C(在Java中,除了基础数据类型外,所有的类型都是引用类型.) Java中的数组在申明时 ...

  2. Java基础复习笔记系列 九 网络编程

    Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ...

  3. Java基础复习笔记系列 八 多线程编程

    Java基础复习笔记系列之 多线程编程 参考地址: http://blog.csdn.net/xuweilinjijis/article/details/8878649 今天的故事,让我们从上面这个图 ...

  4. Java基础复习笔记系列 七 IO操作

    Java基础复习笔记系列之 IO操作 我们说的出入,都是站在程序的角度来说的.FileInputStream是读入数据.?????? 1.流是什么东西? 这章的理解的关键是:形象思维.一个管道插入了一 ...

  5. Java基础复习笔记系列 五 常用类

    Java基础复习笔记系列之 常用类 1.String类介绍. 首先看类所属的包:java.lang.String类. 再看它的构造方法: 2. String s1 = “hello”: String ...

  6. Java基础复习笔记系列 三

    前几节都是基础中的基础,从第三讲的笔记开始,每次笔记针对Java的一个知识块儿.  Java异常处理 1.什么是异常? 异常是指运行期出的错误.比如说:除以一个0:数组越界:读取的文件不存在. 异常处 ...

  7. Java基础复习笔记系列 二

    1.Java中Static的相关用法总结?(静态方法:静态变量:静态代码块) public static void main(String args[])执行的关键,在于有static.有了stati ...

  8. Java基础复习笔记系列 十三 反射机制

    主题:Java反射机制 学习资料参考网址: 1.http://www.icoolxue.com 1.Java反射机制. 各种框架中都使用到了Java的反射机制. 两个类:java.lang.Class ...

  9. 尚学堂JAVA基础学习笔记

    目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...

随机推荐

  1. SpringMVC默认欢迎页面的问题

    使用SpringMVC很长时间,一直有个问题没有搞定,就是web.xml中默认欢迎页面转向控制器的问题. 由于答应朋友明天要交个网站,他们对默认页面有这样的要求,并且最好也别用js等等的跳转:所以今天 ...

  2. AngularJS中转换响应内容

    从远程API获取到的响应内容,通常是json格式的,有时候需要对获取到的内容进行转换,比如去除某些不需要的字段,给字段取别名,等等. 本篇就来体验在AngualrJS中如何实现. 在主页面,还是从co ...

  3. Delphi中COM自动化对象中使用事件

    unit SrvUnit2; interface uses ComObj, ActiveX, AxCtrls, Classes, SrvEvent_TLB, StdVcl, Srvunit1; typ ...

  4. Java中有哪些语法糖?

    不要你写汇编,Java句句是糖 不能同意上面的这句话,要说为什么,首先要定义下面要讲的“语法糖”. 语法糖指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,并没有给语言添加什么新东西,但是 ...

  5. Error-MVC:HTTP Error 500.19 - Internal Server Error 无法访问请求的页面,因为该页的相关配置数据无效。

    ylbtech-Error-MVC:HTTP Error 500.19 - Internal Server Error  无法访问请求的页面,因为该页的相关配置数据无效. 1.返回顶部 1. IIS ...

  6. WinPcap权威指南(一)

    WinPcap是一个开源的网络抓包模块,顾名思义,它只能工作在Windows下,但本文介绍的知识并不局限于任何操作系统和开发语言,因为网络协议本身是没有这些区别的.阅读本指南之前,请先下载WinPca ...

  7. WebMagic编译时提示Failure to transfer org.apache.maven.plugins:maven-surefire-plugin:pom:2.18的解决方法

    问题描述:    从http://git.oschina.net/flashsword20/webmagic 下载最新代码,按照http://webmagic.io/docs/zh/posts/ch3 ...

  8. 自己动手编译Linux内核

    2008年04月27日       整理了一下Linux内核编译的方法,原始内核版本为Linux-2.4.20.8,新内核版本为Linux-2.4.22,其它内核版本编译方法类似.     一 准备工 ...

  9. 单片机成长之路(51基础篇) - 017 C51中data,idata,xdata,pdata的区别(转)

    从数据存储类型来说,8051系列有片内.片外程序存储器,片内.片外数据存储器,片内程序存储器还分直接寻址区和间接寻址类型,分别对应code.data.xdata.idata以及根据51系列特点而设定的 ...

  10. C++11中的右值引用及move语义编程

    C++0x中加入了右值引用,和move函数.右值引用出现之前我们只能用const引用来关联临时对象(右值)(造孽的VS可以用非const引用关联临时对象,请忽略VS),所以我们不能修临时对象的内容,右 ...