如果要在记事本运行的的话需要将记事本名改为 类名.java,然后
javac 类名.java
编译文件,java 类名
运行
冒泡排序
- 冒泡排序的原理很简单:
- 遍历数组,每次比较前后两个数字的大小,将较大的数后移。
- 然后需要进行进行数组长度-1次遍历。
public class Bubble {
public static void main(String[] args) {
int[] nums = {341,92,1,7,432,66,78,9};
Bubble(nums);
for (int num : nums) {
System.out.print(num);
}
}
public static void Bubble(int[] nums){
for(int i = nums.length - 1;i > 0;i --){//注意,这里i从大到小倒叙
for(int j = 0;j < i;j ++){
if(nums[j] > nums[j + 1]){
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
}
}
选择排序
- 假定当前索引所代表的数字为最小值,称该索引为最小索引。遍历数组,如果发现有数字比当前数字小,交换该索引和最小索引。完成一次遍历后,最小索引所代表的数字即为最小值,和当前数字交换位置即可。
- 进行数组长度-1次遍历
public class Choose {
public static void main(String[] args) {
int[] nums = {341,92,1,7,432,66,78,9};
Choose(nums);
for(int num:nums){
System.out.print(num);
}
}
public static void Choose(int[] nums){
for(int i = 0;i < nums.length - 1;i ++){
int minIndex = i;
for(int j =i+1;j < nums.length;j ++){
if(nums[j] < nums[minIndex]){
minIndex = j;
}
}
int temp = nums[minIndex];
nums[minIndex] = nums[i];
nums[i] = temp;
}
}
}
插入排序
- 将待排序数组分为两部分:已排序数组和未排序数组。
- 取未排序数组的第一个数,倒叙遍历已排序数组,依次和已排序数组中的数比较,若该数小于已排序数组中的数,则交换位置。
public class Insert {
public static void main(String[] args) {
int[] nums = {341,92,1,7,432,66,78,9};
Insert(nums);
for (int num : nums) {
System.out.print(num);
}
}
public static void Insert(int[] nums){
for(int i = 0;i < nums.length - 1;i ++){
for(int j = i;j >= 0;j --){
if(nums[j + 1] < nums[j]){
int temp = nums[j + 1];
nums[j + 1] = nums[j];
nums[j] = temp;
}
}
}
}
}
希尔排序
- 定义增量长h使得数组分成多个组,每组两个数字进行比较交换
- 缩小增量长,当h<1时结束排序
- 在希尔排序中,增长量h并没有固定的规则;我这里假定了一种h的限制方法
public class Shell {
public static void main(String[] args) {
int[] nums = {341,92,1,7,432,66,78,9};
Shell(nums);
for (int num : nums) {
System.out.print(num);
}
}
public static void Shell(int nums[]){
int N = nums.length;
//一种h的定义方法
int h = 1;
while(h < N / 2){
h = h * 2 + 1;
}
while(h >= 1){
for(int i = h;i < N;i ++){
for(int j = i;j >= h;j -= h){
if(nums[j-h] > nums[j]){
int temp = nums[j-h];
nums[j-h] = nums[j];
nums[j] = temp;
}else{
break;
}
}
}
h = h/2;
}
}
}
归并排序
- 先分(sort),再合(Merge)
- 分治法
- 利用了递归(所以不能忘了退出条件)
- 利用了一个辅助数组,在merge中用到的,最后也要将辅助数组的内容还给原数组
public class Merge {
public static void main(String[] args) {
int[] nums = {341,92,1,7,432,66,78,9};
sort(nums);
for (int num : nums) {
System.out.print(num);
}
}
static int[] assist;
public static void sort(int[] nums){
assist = new int[nums.length];
int lo = 0;
int hi = nums.length - 1;
sort(nums,lo,hi);
}
public static void sort(int[] nums, int lo, int hi) {
if(hi <= lo){
return;
}
int mid = lo + (hi-lo)/2;
sort(nums,lo,mid);//分1
sort(nums,mid+1,hi);//分2
merge(nums,lo,mid,hi);//治
}
public static void merge(int[] nums,int lo,int mid,int hi){
int i = lo;//指向辅助数组的头
int p1 = lo;//指向(被分开的)前一个数组的头
int p2 = mid + 1;//指向(被分开的)后一个数组的头
while(p1 <= mid && p2 <= hi){//根据两个数组中数的大小,放到辅助数组中
if(nums[p1] < nums[p2]){
assist[i++] = nums[p1++];
}else{
assist[i++] = nums[p2++];
}
}
while(p1 <= mid){//清空(被分开的)前一个数组,全部放到辅助数组
assist[i++] = nums[p1++];
}
while(p2 <= hi){清空(被分开的)后一个数组,全部放到辅助数组
assist[i++] = nums[p2++];
}
for(int index = lo;index <= hi;index ++){//辅助数组的内容还给原数组
nums[index] = assist[index];
}
}
}
快速排序
- 快速排序的原理和归并排序类似,不过归并排序是从中间切分,并且切分后需要再合起来。而快速排序需要设计一个算法找到一个切分值,我们对切分好的每一段进行排序
- 找到切分值的算法:假定我们的第一个元素就是切分值,我们通过调整使得他称为真正的切分值:定义一个指向头以及一个指向尾部往后一位的指针,一个往后扫描,当扫描到某个数(下标left)大于假定的切分值时停止;一个往前扫描,当扫描到某个数(下标right)小于假定的切分值时停止。
- 如果left >= right就直接退出了。这个时候一般left == right,他们的值已经达到了切分值的要求,我们将这个值和第一个元素交换,就达成了目标。
- 否则应该交换两个数的位置,使得左边的都小于切分值,右边的都大于切分值。利用一个while循环继续这个操作。
public class Quick {
public static void main(String[] args) {
int[] nums = {341,92,1,7,432,66,78,9};
sort(nums);
for (int num : nums) {
System.out.print(num);
}
}
public static void sort(int[] nums){
int lo = 0;
int hi = nums.length - 1;
sort(nums,lo,hi);
}
public static void sort(int[] nums,int lo,int hi){
if(lo >= hi){
return;
}
int p1 = part(nums,lo,hi);//找出切分值
sort(nums,lo,p1-1);
sort(nums,p1+1,hi);
}
public static int part(int[] nums, int lo, int hi){
int key = nums[lo];
int left = lo;
int right = hi + 1;
while(true){
while(key < nums[--right]){
if(right == lo){
break;
}
}
while(key > nums[++left]){
if(left == hi){
break;
}
}
if(left >= right){
break;
}else{
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
int ktemp = nums[lo];
nums[lo] = nums[right];
nums[right] = ktemp;
return right;
}
}
堆排序
- 堆排序需要首先构造堆,然后再进行排序。我们这里利用的是大顶堆,所谓大顶堆也就是从顶向下,数字是从大到小的。所以我们每次交换大顶堆的第一个和未排序的最后一个,(每次交换完后需要进行一次下沉以保证其大顶堆的特性),这样交换完成后就可以实现从小到大的排序。
- 如何构造大顶堆?从二分之一处往前扫描,不停的下沉。
- 当然也不能忘记将堆的内容还给数组。
public class HeapSort {
public static void main(String[] args) {
int[] nums = {341,92,1,7,432,66,78,9};
sort(nums);
for(int num:nums){
System.out.print(num);
}
}
public static void sort(int[] nums){
//1.建立堆heap|堆的0号位置是空出来的,所以用一个新的数组进行复刻
int[] heap = new int[nums.length + 1];
System.arraycopy(nums,0,heap,1,nums.length);
for(int i = (heap.length - 1) / 2;i > 0;i --){//这里是>0不是>=0!!!!!!!!!!
sink(heap,i,heap.length-1);//-1是因为堆长度多出来一位
}
//2.排序|交换堆顶元素和最后一个元素并下沉
for(int i = heap.length - 1;i > 1;i--){
int temp = heap[i];
heap[i] = heap[1];
heap[1] = temp;
sink(heap,1,i-1);//这里i-1也很容易错
}
//3.收尾工作,把堆还给nums
System.arraycopy(heap,1,nums,0,nums.length);
}
//下沉
//找到子节点中较大的值的下标,如果target < 较大的值,就需要交换
//大大的问题,堆的大小直接显示在序号上了//这里max代表的是下标
public static void sink(int[] heap,int target,int range){
while(2 * target <= range){//至少左子节点
int max = 2 * target;//这里max代表的是下标
if(2 * target + 1 <= range){//如果存在右子节点
if(heap[2 * target + 1] > heap[2 * target]){
max = 2 * target + 1;
}
}
if(heap[target] < heap[max]){//如果target < 较大的值,就需要交换
int temp = heap[target];
heap[target] = heap[max];
heap[max] = temp;
}
//更新target的值,进行下一个
target = max;
}
}
}
基数排序(也叫桶排序)
- 基础排序需要对每一位(个、十、百、千、万)进行排序,每一位的排序都需要放进桶,再拿回数组,这样就使得每一位都有顺序
- 首先 ,确定他的最高位是多少,找出最大数,最大数的位数就是最高位
- 造桶,造一个计数器
- 循环操作(放进桶,拿回数组)
package com.zhang.eightsort;
public class BaseSort {
public static void main(String[] args) {
int[] nums = {341,92,1,7,432,66,78,9};
sort(nums);
for (int num : nums) {
System.out.print(num+" ");
}
}
public static void sort(int[] nums){
//1.找出最大位是哪一位| 先找最大的数,然后看他的位数
int maxNum = nums[0];
for (int i = 0; i < nums.length; i++) {
if(nums[i] > maxNum){
maxNum = nums[i];
}
}//331
int maxLen = Integer.toString(maxNum).length();//3
//2.开始造桶 10 x nums.length
//并且把数据都放进桶里
int[][] bucket = new int[10][nums.length];
int[] counts = new int[10];//创建10个计数器
int div = 1;
for(int i = 0;i < maxLen;i ++){//每次都要放进桶再拿出来
for(int j = 0 ;j < nums.length;j ++){
int temp = nums[j] / div % 10;//比如说余3
bucket[temp][counts[temp]++] = nums[j];
}
div *= 10;
int total = 0;
//从桶里把数据放回数组
for(int n = 0;n < 10;n++){//10 个桶
for(int j = 0;j < counts[n];j ++){
nums[total++] = bucket[n][j];//total别忘了++
}
counts[n] = 0;//这个清空桶的操作还挺关键,不然会数组下标越界
}
}//这个括号放在这也有讲究,每排一次都要放回一次数组中。
}
}