数据结构——八大排序

目录

冒泡排序

选择排序

插入排序

希尔排序(缩小增量排序)

基数排序

快速排序

归并排序

堆排序


冒泡排序

时间复杂度:O(n^2)

前后两个数据进行对比----交换

定义i和i+1两个游标,将其指向的值进行对比----交换(一轮下来一定有一个数据有序),最多经过数组长度轮数据就会变得有序

//冒泡排序
import java.util.Arrays;

public class BubbleSort {
	
	public static void main(String[] args) {
		int[] arr = {5,7,4,2,0,3,1,6};
		sort(arr);
		System.out.println(Arrays.toString(arr));
	}
	public static void sort(int[] arr) {
		for(int j=0;j<arr.length;j++) {
			for(int i=0;i<arr.length-1;i++) {
				if(arr[i]>arr[i+1]) {
					//进行交换
					int temp = arr[i];
					arr[i] = arr[i+1];
					arr[i+1] = temp;
				}
			}
		
		}
	}
}

选择排序

时间复杂度:O(n^2)

去找待排序数组当中的最小值和数组当中的第一个位置的数进行交换,找的过程也是一次对比

//选择排序
import java.util.Arrays;

public class SelectSort {
	public static void main(String[] args) {
		int[] arr = {5,76,45,2,10,3,13,60};
		sort(arr);
		System.out.println(Arrays.toString(arr));
	}
	public static void sort(int[] arr) {
		for(int j=0;j<arr.length;j++) {
			int min = arr[j];
			int minIndex = j;
			//找真正的最小值
			for(int i=j;i<arr.length;i++) {
				if(arr[i]<min) {
					min = arr[i];
					minIndex = i;
				}
			}
			//真正的最小值和待排数组中的第一个交换
			arr[minIndex] = arr[j];
			arr[j] = min;
		}
		
	}
}

插入排序

时间复杂度:O(n^2)

冒泡排序的逆用

假设数组当中的第一个数是一定排好序的,后边待排序数据要插入到已经排好序的数组当中去

i游标:指向待排序数组的第一个

j游标:指向已经排好序数组的最后一个

//插入排序
import java.util.Arrays;

public class InsertSort {
	public static void main(String[] args) {
		int[] arr = {5,7,4,2,0,3,1,6};
		sort(arr);
		System.out.println(Arrays.toString(arr));
	}
	public static void sort(int[] arr) {
		for(int i=1;i<arr.length;i++) {
			//用j和j+1进行比较交换
			for(int j=i-1;j>=0;j--) {
				if(arr[j]>arr[j+1]) {
					//进行交换
					int temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}else {
					break;
				}
			}
		}
	}
}

希尔排序(缩小增量排序)

时间复杂度:O(nlogn)

是在插入排序的基础之上得来的

在插入排序当中越小越靠后的数据,移动的次数会明显增加

分组,先将组内的数据向前移动

//希尔排序
import java.util.Arrays;

public class ShellSort {
	public static void main(String[] args) {
		int[] arr = {5,7,4,2,0,3,1,6};
		sort(arr);
		System.out.println(Arrays.toString(arr));
	}
	public static void sort(int[] arr) {
		for(int grp=arr.length/2;grp>0;grp=grp/2) {
			for(int i=grp;i<arr.length;i++) {
				//arr[j]  arr[j+grp]进行比较
				for(int j=i-grp;j>=0;j=j-grp) {
					if(arr[j]>arr[j+grp]) {
						int temp = arr[j];
						arr[j] = arr[j+grp];
						arr[j+grp] = temp;
					}else {
						break;
					}
				}
			}
		}
	}
}

基数排序

时间复杂度:O(kn)

定义0-9十个桶,先排序个位,排序十位,排序百位,......

//基数排序
import java.util.Arrays;

public class RadixSort {
	public static void main(String[] args) {
		int[] arr = {50,17,41,20,101,35,11,62,74,26,48,45,59,32,21,102,301};
		sort(arr);
		System.out.println(Arrays.toString(arr));
	}
	
	public static void sort(int[] arr) {
		//取最大值计算最大值的位数
		int max = arr[0];
		for(int j=0;j<arr.length;j++) {
			if(arr[j]>max) {
				max = arr[j];
			}
		}
		//最大值的位数
		int maxLen = (max+"").length();

		//定义桶
		int[][] bucket = new int[10][arr.length];
		
		//定义桶记录工具
		int[] elementCounts = new int[10];
		
		int n = 1;
		//放入取出执行maxLen值
		for(int m=0;m<maxLen;m++) {
			//遍历数组,将数组中的数据放入桶中
			for(int i=0;i<arr.length;i++) {
				//element代表个位数值,也代表要放入哪个桶
				int element = arr[i]/n%10;
				//读取桶记录中的数值
				int count = elementCounts[element];
				//数据放入
				bucket[element][count] = arr[i];
				//桶记录中数据加一
				elementCounts[element]++;
			}
			//将桶中的数值取出
			int index = 0;//定义index游标,遍历待排序数组
			for(int k=0;k<elementCounts.length;k++) {
				if(elementCounts[k]!=0) {
					//桶中有数据,将数据取出
					for(int l=0;l<elementCounts[k];l++) {
						arr[index] = bucket[k][l];
						index++;
					}
				}
				//清空桶记录
				elementCounts[k] = 0;
			}
			n = n*10;
		}
	}
}

快速排序

时间复杂度:O(nlogn)

1.将待排序数组的第一个数作为基准数

2.定义left和right两个游标,分别指向数组的两侧

3.right游标先移动去找比当前基准数小的数据,找到后停止

4.left游标后移动去找比当前基准数大的数据,找到后停止

5.如果left和right游标没有相遇,则交换left和right指向的值

6.如果left和right相遇,那么相遇位置的值和基准数交换

将数组以基准数为中心拆分成左右两部分,重新执行上面第一步

每一个元素都被拆开,那么程序停止,数组有序

//快速排序
import java.util.Arrays;

public class QuickSort {
	public static void main(String[] args) {
		int[] arr = {5,7,4,2,0,3,1,6};
		quickSort(arr,0,arr.length-1);
		System.out.println(Arrays.toString(arr));
	}
	public static void quickSort(int[] arr,int left,int right) {
		if(left>=right) {
			return;
		}
		//定义基准数
		int base = arr[left];
		//定义i游标 j游标
		int i = left;
		int j = right;
		
		while(i!=j) {
			//j游标从后往前移动,找比基准数小的
			while(arr[j]>=base && i<j) {
				j--;
			}
			//i游标从前往后移动,找比基准数大的
			while(arr[i]<=base && i<j) {
				i++;
			}
			//i和j进行交换
			int temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
		//i和j相遇  基准数和相遇位置进行交换
		arr[left] = arr[i];
		arr[i] = base;
		
		//排序左边
		quickSort(arr,left,i-1);
		
		//排序右边
		quickSort(arr,i+1,right);
	}
}

归并排序

时间复杂度:O(nlogn)

先拆分,再合并,在合并的过程中借助临时空间进行排序

拆分:从中间位置拆开,数据分成左右两部分,继续进行拆分,直到数据拆分成一个一个的时候停止

//归并排序
import java.util.Arrays;

public class MergeSort {
	public static void main(String[] args) {
		int[] arr = {5,7,4,2,0,3,1,6};
		mergeSort(arr,0,arr.length-1);
		System.out.println(Arrays.toString(arr));
	}
	//拆分
	public static void mergeSort(int[] arr,int left,int right) {
		//递归出口
		if(left==right) {
			return;
		}
		int mid = (left+right)/2;
		//向左拆分
		mergeSort(arr,left,mid);
		//向右拆分
		mergeSort(arr,mid+1,right);
		//合并
		merge(arr,left,right,mid);
	}
	//合并
	public static void merge(int[] arr,int left,int right,int mid) {
		//定义第一段和第二段的开始
		int s1 = left;
		int s2 = mid+1;
		//定义临时空间
		int[] temp = new int[right-left+1];
		int index = 0;//定义游标遍历临时空间
		//判断s1和s2指向的数据大小,将其存入临时数组
		while(s1<=mid&&s2<=right) {
			if(arr[s1]<arr[s2]) {
				temp[index] = arr[s1];
				s1++;
				index++;
			}else {
				temp[index] = arr[s2];
				s2++;
				index++;
			}
		}
		//判断s1中是否有数据,如果有将其放入临时数组
		while(s1<=mid) {
			temp[index] = arr[s1];
			s1++;
			index++;
		}
		//判断s2中是否有数据,如果有将其放入临时数组
		while(s2<=right) {
			temp[index] = arr[s2];
			s2++;
			index++;
		}
		//将临时数组中的数据写回原数组
		for(int j=0;j<temp.length;j++) {
			arr[left+j] = temp[j];
		}
	}
}

堆排序

时间复杂度:O(nlogn)

1.利用完全二叉树构建大顶堆

2.堆顶元素和堆底元素进行交换,除堆底元素之外其余元素继续构建大顶堆

3.重复2,直到所有元素都不参与构建,整个数组排序完成

完全二叉树:数据从上到下,从左到右排列

大顶堆:父节点的值大于或等于其左右孩子的值

如何构建?从后往前一次检测所有的节点是否符合大顶堆,如果符合,则检测下一个元素;如果不符合,则进行调整让其符合大顶堆

如何检测和调整?

第一次构建大顶堆 1.定义parent游标指向检测的节点 2.定义parent的左孩子child(有孩子一定会有左孩子) 3.判断有没有右孩子,如果有右孩子,左右孩子进行比较,child指向左右孩子当中的最大值 4.parent和指向的值进行比较,若parent的值大,则符合大顶堆;若parent的值小,父子节点进行交换,parent指向child,child指向其左右孩子的最大值,继续进行比较;直到child为空或parent指向的值大,则停止

之后构建大顶堆 parent指向堆顶元素,child指向其左右孩子的最大值,parent和指向的值进行比较,若parent的值大,则符合大顶堆;若parent的值小,父子节点进行交换,parent指向child,child指向其左右孩子的最大值,继续进行比较;直到child为空或parent指向的值大,则停止

arr[i]的左孩子arr[2i+1] arr[i]的右孩子arr[2i+2] arr[i]的父节点arr[(i-1)/2]

//堆排序
import java.util.Arrays;

public class HeapSort {
	public static void main(String[] args) {
		
		int[] arr = {5,7,4,2,0,3,1,6};
		
		//第一大步,构建大顶堆
		for(int p=arr.length-1;p>=0;p--) {
			adjust(arr,p,arr.length);
		}
		
		//第二大步,堆顶和堆底进行交换,除堆底外剩余元素继续构建大顶堆
		for(int i=arr.length-1;i>=0;i--) {
			int temp = arr[0];
			arr[0] = arr[i];
			arr[i] = temp;
			adjust(arr,0,i);
		}
		
		System.out.println(Arrays.toString(arr));
		
	}
	//堆的维护
	public static void adjust(int[] arr,int parent,int length) {
		//定义左孩子
		int child = 2*parent+1;
		while(child<length) {
			//定义右孩子
			int rchild = child+1;
			if(rchild<length && arr[rchild]>arr[child]) {
				child++;
			}
			//child指向的是左右孩子当中的最大值
			
			//父子节点进行比较
			if(arr[parent]<arr[child]) {
				//父子节点进行交换
				int temp = arr[parent];
				arr[parent] = arr[child];
				arr[child] = temp;
				//parent指向child,child继续指向其左右孩子的最大值
				parent = child;
				child = 2*child+1;
			}else {
				break;
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值