经典排序算法-Java
内排序:排序操作在内存中完成;
外排序:因为数据量较大,所以把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;
稳定:x=y,如果x原本在y前面,排序之后x仍在y前面;
不稳定:x=y,如果x原本在b前面,排序之后x可能会出现在y后面;
时间复杂度: 算法程序执行所耗费的时间成本;
空间复杂度:运行完算法程序所需要的内存大小
基本排序算法:冒泡排序(稳定),插入排序(稳定),选择排序(不稳定)
时间复杂度:O(n^2)
空间复杂度:O(1)
其他排序算法:
归并排序(稳定)——时间复杂度:O(nlogn)、空间复杂度:O(n)
一、冒泡排序
两个for循环,外循环每次排好一个,内循环控制比较的范围(因为已经有i个是排好的),if语句判断是否要交换,变量tmp用来暂存要交换的元素
public class bubbleSort {
//大的沉到尾部
public static void bubble_sort(int[] arr){
int tmp;//暂存要交换的元素
int len = arr.length;
for (int i = 0;i < len;i++){//外循环,每次循环确定一个最大元素
for (int j = 1;j < len-i;j++){//内循环,后面的i个已经排好
if (arr[j-1] > arr[j]){//如果前一个比后一个大,交换
tmp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = tmp;
}
}
}
}
public static void main(String[] args) {
int[] arr = {2,5,1,7,4,8,3,1,5,9};
bubble_sort(arr);
for (int a = 0;a < arr.length;a++){
System.out.print(arr[a]+" ");
}
}
}
二、选择排序
public class selectionsort {
public static void main(String[] args) {
int[] arr = {20,40,30,10,60,50};
selectionsort ins = new selectionsort();
ins.select_sort(arr);
}
public void select_sort(int[] arr){
int minpoint;//用来记录最小的元素的下标
int len = arr.length;//记录长度,可要可不要
int temp;//交换两个元素时过渡使用
for (int i = 0;i < len-1;i++){//外循环
minpoint = i;//初始假设第一个元素是最小的元素,记录下标
for (int j = i+1;j < len;j++){//比较找出最小元素,前面的i个已经排好,所以从i+1个开始找
if(arr[minpoint] > arr[j]){//比较
minpoint = j;//更新最小记录下标
}
}
if (minpoint!=i){//跟原来的不相等则交换,其实意义不大,就是处理最后一个
temp = arr[minpoint];
arr[minpoint] = arr[i];
arr[i] = temp;
}
}
}
}
三、插入排序
public class insertSort {
public static void insert_sort(int[] arr){
int temp;
for (int i = 1;i < arr.length;i++){//注意要从1开始,因为插入的位置最小也是1前面,不能是0前面
int p = i-1;//记录要开始比较的位置,即第i个元素的前一个
temp = arr[i];//记录当前的第i个元素,因为我们把元素往后移动的时候会覆盖
while(p >= 0 && arr[p] > temp){//当前的小于前面的,前面的那个数往后移动一位
arr[p+1] = arr[p];
p--;//往前继续比较
}
//直到找到需要插入的位置
arr[p+1] = temp;
}
}
public static void main(String[] args) {
int[] arr = {8, 2, 4, 9, 3, 6};
insert_sort(arr);
for (int a = 0; a < arr.length; a++) {
System.out.print(arr[a] + " ");
}
}
}
二分插入排序
就是寻找插入位置时使用二分查找
public class insertSort {
//优化,加入二分查找来确定插入位置
public static void binarysearch(int[] arr){
for (int i = 1;i < arr.length;i++){//注意要从1开始,因为插入的位置最小也是1前面,不能是0前面
if (arr[i] < arr[i-1]){
int tmp = arr[i];
int low = 0;
int high = i-1;
while(low <= high){//二分停下条件,“=”是为了解决偶数个元素问题
int mid = (low+high)/2;//取中间元素
if (arr[mid] > tmp){
high = mid-1;
}else {
low = mid+1;
}
}
for (int j = i-1;j >= low;j++){
arr[j+1] = arr[j];
}
arr[low] = tmp;
}
}
}
public static void main(String[] args) {
int[] arr = {8, 2, 4, 9, 3, 6};
binarysearch(arr);
for (int a = 0; a < arr.length; a++) {
System.out.print(arr[a] + " ");
}
}
}
四、归并排序
public class merge {//归并排序需要2个方法,一个用于递归拆分成单个元素,一个用于比较排序
public static void main(String[] args) {
int[] arr = {3,5,7,1,8,6,3,96,3,33};
merge_sort(arr,0,arr.length-1);
for (int a = 0;a < arr.length;a++){
System.out.print(arr[a]+" ");
}
}
public static void merge_sort(int[] arr, int left, int right){
int mid = (left+right)/2;
if(left < right){//每一次都要拆分,而且调用归并排序方法
merge_sort(arr,left, mid);//左边部分,递归拆分
merge_sort(arr,mid+1,right);//右边部分,递归拆分
merge(arr,left,right,mid);//合并每两部分
}
}
public static void merge(int[] arr,int left,int right,int middle){
int[] temp = new int[right-left+1];
int i = 0;
int j = left;//为了能记录住left的值,覆盖原数组时要靠它定位,我们让j去变化
int k = middle+1;
while (j <= middle && k <= right){
if (arr[j] < arr[k]){
/*temp[i] = arr[j];
* i++;
* j++;*/
temp[i++] = arr[j++];//优化
}else{
temp[i++] = arr[k++];
}
}
while(j <= middle){
temp[i++] = arr[j++];
}
while(k <= right){
temp[i++] = arr[k++];
}
for (int a = 0;a < temp.length;a++){
arr[a+left] = temp[a];//理解为什么要arr[a+left],+left是为了定位当前归并的位置
}
}
}