排序算法
冒泡排序(交换排序)
描述
冒泡排序是一种简单的比较类排序算法。排序的时候重复的走访过要排序的数列,一次比较两个元素,如果他们的顺序错误,那么就交换回来,走访过一遍后再来一遍,直到数列有序。
具体划分为四步:
1–比较相邻的元素,如果第一个比第二个大,交换
2–从头至尾的重复1的步骤,这样最后一个元素就是最大的
3–针对所有的元素重复以上的步骤,除了最后一个。
4–重复1到3步骤直到完成。
代码
public class BubbleSort {
public static void main(String[] args) {
Random random = new Random();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i, random.nextInt(1000));
}
System.out.println(list);
bubbleSort(list);
System.out.println(list);
}
public static List<Integer> bubbleSort(List<Integer> list){
int size = list.size();
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size-1-i; j++) {
if (list.get(j)>list.get(j+1)){
int temp = list.get(j);
list.set(j,list.get(j+1));
list.set(j+1,temp);
}
}
}
return list;
}
}
public class BubbleSort {
public static void main(String[] args) {
int[] nums = new int[]{1,5,6,347,23,3,7,23,85};
bubbleSort(nums);
for (int i=0;i<nums.length;i++) {
System.out.print(nums[i]+" ");
}
}
public static int[] bubbleSort(int[] nums){
int length = nums.length;
for (int i = 0; i < length - 1; i++) {
for (int j = 0; j < length - 1 - i; j++) {
if (nums[j]>nums[j+1]){
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
return nums;
}
}
时间复杂度和空间复杂度
时间复杂度,最坏 O ( n 2 ) O(n^2) O(n2),最好 O ( n ) O(n) O(n);空间复杂度 O ( 1 ) O(1) O(1)。稳定的排序算法。
快速排序(交换排序)
描述
快排通过一趟排序将待排序记录分成两部分,其中一部分比另一部分全都要小,再递归进行排序,最终有序。
具体来说:
1. 从数组中选出一个基准元素-pivot和left、right;
2. 经过一次排序,把比pivot大的都放在pivot右边,比他小的放在pivot左边。(第一次从最右边往左开始找right–,只要遇到了一个比pivot小的数,就把这个数和left交换;然后从最左边开始找left++,只要遇到比pivot大的数就和right交换)
3. 递归的进行1和2步骤,直到所有元素都有序。
代码:
public class QuickSort {
public static void main(String[] args) {
int[] nums = {1,32,6,2,67,8,45,87,89,32,4,56,3};
quickSort(nums,0,nums.length-1);
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i]+" ");
}
}
public static void quickSort(int[] nums,int left,int right){
if (left>=right) return;
int l = left, r = right;
int pivot = nums[left];
while (l<r){
//从右向左找第一个比pivot小的值
while (l<r && nums[r]>=pivot) r--;
if (l<r){
nums[l] = nums[r];
l++;
}
//从左边找第一个比pivot大的值
while (l<r && nums[l]<=pivot) l++;
if (l<r){
nums[r] = nums[l];
r--;
}
}
//最后把pivot填入坑中
nums[l] = pivot;
quickSort(nums,left,l-1);
quickSort(nums,r+1,right);
}
}
时间和空间复杂度
时间复杂度最好为 O ( n l o g n ) O(nlogn) O(nlogn),最差为 O ( n 2 ) O(n^2) O(n2);空间复杂度 O ( n l o g n ) O(nlogn) O(nlogn);不稳定的排序
简单插入排序
描述
选中一个有序数列,开始时为第一个元素;从前往后构造有序数列,将后面无序队列中的元素一个个放入前面有序队列中。
代码
public class InsertSort {
public static void main(String[] args) {
int[] nums = {1,32,6,35,33,87,423,3,5,8};
insertSort(nums);
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i]+" ");
}
}
public static void insertSort(int[] nums){
int length = nums.length;
int index = 0,cur = 0;
for (int i = 1; i < length; i++) {
index = i - 1;
cur = nums[i];
while (index>=0&&nums[index]>cur){
nums[index + 1] = nums[index];
index--;
}
nums[index+1] = cur;
}
}
}
时间和空间复杂度
时间复杂度平均为 O ( n 2 ) O(n^2) O(n2),最好为 O ( n ) O(n) O(n);空间复杂度为 O ( 1 ) O(1) O(1);稳定的排序算法。
希尔排序(插入排序)
描述
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止
代码
public class ShellSort {
public static void main(String[] args) {
int[] nums = {110,98,2,4,6,32,7,32,38,5,54,62};
shellSort(nums);
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i]+" ");
}
}
public static void shellSort(int[] nums){
int index = nums.length/2;
while (index>=1){
for (int i = index; i < nums.length; i++) {
int temp = nums[i];
int j = i - index;
while (j>=0&&nums[j]>temp){
nums[j+index] = nums[j];
j = j - index;
}
nums[j+index] = temp;
}
index = index/2;
}
}
}
时间和空间复杂度
时间复杂度平均 O ( n 1.3 ) O(n^{1.3}) O(n1.3),最差 O ( n 2 ) O(n^2) O(n2),最好 O ( n ) O(n) O(n);空间复杂度 O ( 1 ) O(1) O(1)。不稳定的排序算法。
简单选择排序
描述
首先在待排序序列中找到最小(大)的元素,放在排序序列的起始部位;然后再从待排序序列中继续寻找到最小(大)的元素放到已排序序列的末尾,直到所有元素都排好序。
代码
public class SelectionSort {
public static void main(String[] args) {
int[] nums = {2,5,6,1,3,64,23,56,13,75,23};
selectionSort(nums);
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i]+" ");
}
}
public static void selectionSort(int[] nums){
int length = nums.length;
for (int i = 0; i < length; i++) {
int sentinel = i;
for (int j = i + 1; j < length; j++) {
if (nums[sentinel] > nums[j]){
sentinel = j;
}
}
int temp = nums[i];
nums[i] = nums[sentinel];
nums[sentinel] = temp;
}
}
}
时间和空间复杂度
时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( 1 ) O(1) O(1)。不稳定的排序算法
堆排序(选择排序)
描述
堆排序是利用堆这种数据结构所设计的一种排序算法。
堆的性值:每个节点的值都大于或等于其左右孩子节点的值(大根堆);每个节点的值都小于或等于其左右孩子节点的值(小根堆)。;堆是***完全二叉树***。
基本过程:
1.将待排序序列构建成一个大顶堆(升序用大顶堆,降序用小顶堆)。
2.将堆顶元素和末尾元素交换,将最大元素下沉到数组末端。
3.重新调整结构,使其满足堆定义;然后继续交换堆顶元素与当前末尾元素。反复进行调整+交换,直到整个序列有序。
堆排序的性值:
大顶堆:
a
r
r
[
i
]
>
=
a
r
r
[
2
i
+
1
]
&
&
a
r
r
[
i
]
>
=
a
r
r
[
2
i
+
2
]
arr[i] >= arr[2i + 1] \&\& arr[i] >= arr[2i +2]
arr[i]>=arr[2i+1]&&arr[i]>=arr[2i+2]
小顶堆:
a
r
r
[
i
]
<
=
a
r
r
[
2
i
+
1
]
&
a
r
r
[
i
]
<
=
a
r
r
[
2
i
+
2
]
arr[i] <= arr[2i + 1] \& arr[i] <= arr[2i +2]
arr[i]<=arr[2i+1]&arr[i]<=arr[2i+2]
代码
public class HeapSort {
public static void main(String[] args) {
int[] arrs = {2,4,74,21,8,5,12,55,33,66,99,11};
heapSort(arrs);
for (int i=0;i<arrs.length;i++) {
System.out.print(arrs[i]+" ");
};
}
public static void heapSort(int[] arrs){
//构建大根堆
for (int i = arrs.length/2 - 1; i >= 0; i--) {
adjustHeap(arrs,i,arrs.length);
}
//调整堆结构 交换堆顶元素和堆末元素
for (int i = arrs.length - 1; i > 0; i--) {
swap(arrs,0,i);
adjustHeap(arrs,0,i);
}
}
public static void adjustHeap(int[] arrs, int i, int len) {
int temp = arrs[i];//初始调整的父节点---如果父节点被交换了,用temp保留最后赋值到目的节点
for (int k = i*2 + 1; k < len; k = k*2 + 1){//从i节点的左子节点开始(2i+1)
if (k+1 < len && arrs[k] < arrs[k+1]){//如果左子节点小于右子节点,k指向右子节点
k++;
}
if (arrs[k] > temp){//如果子节点大于父节点,将子节点赋值给父节点(不是交换)
arrs[i] = arrs[k];
i = k;
}else {
break;
}
}
arrs[i] = temp;
}
public static void swap(int[] arrs, int i, int j){
int temp = arrs[i];
arrs[i] = arrs[j];
arrs[j] = temp;
}
}
时间和空间复杂度
时间复杂度 O ( n l o n g ) O(nlong) O(nlong),空间复杂度 O ( 1 ) O(1) O(1)。不稳定的排序算法。
归并排序
思想
归并排序是分治法的一个典型应用。将待排序序列分成长度相等的两个子序列,对这个两个子序列分别采用归并排序;最后将排序好的子序列合并成一个最终的有序序列。
代码
public class MergeSort {
public static void main(String[] args) {
int[] arrs = {2,5,3,11,3,63,67,33,55,11,78};
mergeSort(arrs);
System.out.println(Arrays.toString(arrs));
}
public static void mergeSort2(int[] arrs){//迭代法
int len = arrs.length;
int block,start;
int[] result = new int[len];
for (block = 1; block < len*2; block *= 2) {
for (start = 0; start < len; start += 2*block){
int low = start;
int mid = (start + block) < len ? (start + block) : len;
int high = (start + 2*block) < len ? (start + 2*block) :len;
//两个块的起始下标和结束下标
int start1 = low, end1 = mid;
int start2 = mid, end2 = high;
//对这两个block进行归并排序
while (start1 < end1 && start2 < end2){
result[low++] = arrs[start1] < arrs[start2] ? arrs[start1++] : arrs[start2++];
}
while (start1 < end1){
result[low++] = arrs[start1++];
}
while (start2 < end2){
result[low++] = arrs[start2++];
}
}
int[] temp = arrs;
arrs = result;
result = temp;
}
}
public static void mergeSort(int[] arrs){//递归
int len = arrs.length;
int[] res = new int[len];
mergeSortRecursive(arrs,res,0,len - 1);
}
public static void mergeSortRecursive(int[] arrs,int[] result,int start,int end){
if (start>=end) return;
int len = end - start, mid = (len >> 1) + start;
int start1 = start, end1 = mid;
int start2 = mid + 1, end2 = end;
mergeSortRecursive(arrs,result,start1,end1);
mergeSortRecursive(arrs,result,start2,end2);
int k = start;
while (start1 <= end1 && start2 <= end2){
result[k++] = arrs[start1] < arrs[start2] ? arrs[start1++] : arrs[start2++];
}
while (start1 <= end1){
result[k++] = arrs[start1++];
}
while (start2 <= end2){
result[k++] = arrs[start2++];
}
for (k = start;k<=end;k++){
arrs[k] = result[k];
}
}
}
时间和空间复杂度
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn),空间复杂度 O ( n ) O(n) O(n)。归并排序是稳定的排序算法