算法整理01——排序算法

最近想整理整理一下所学的一些东西,仅仅总结自己所学的,内容参考了网上和一些视频,尽量给出原文链接。

排序算法

1、冒泡排序:思想:在数组中,从第一个数组开始遍历,每一次遍历确定最大一个数。显然时间复杂度为O(N^2)

2、选择排序:思想:遍历数组,找到数组中每一个位置的值,如第一个位置就是最小的,遍历数组,找到最小的放在第一个位置。时间复杂度为O(N^2)

3、插入排序:思想:类似打牌的时候插入扑克牌,假设原来的数已经是整理好的,插入进来和左边的数比,大则停止,小则调换。时间复杂度为O(N^2)

       public static void insertionSort(int[] arr) {
		if(arr == null || arr.length < 2) return;
		//出错的地方:写成了i < arr.length-1,这样最后一个数组没有比较过。。。注意细节。
		for(int i = 1; i < arr.length ; i++) {
			//出错的地方:外圈的i不应该在内圈有变化,只可以当标记,不可以改变它。
			for(int j = i-1; j > -1 && arr[j] > arr[j+1]; j--) {
				swap(arr, j+1, j);
				
			}
		}
	}
	//交换数组中两个元素最快的方式
	public static void swap(int[] arr, int i, int j) {
		arr[i] = arr[i] ^ arr[j];
		arr[j] = arr[i] ^ arr[j];
		arr[i] = arr[i] ^ arr[j];
	}

4、归并排序:思想:递归的思想,如果整个数组分成两半,每一半都是排好序的,最后我只是需要将两半合并到一起就好了。每一办我继续用这个思想。代码思路:主代码,合并代码,在主代码里面递归。

时间复杂度分析:分成了logN次,每一次都需要合并 所以是O(N*Log N)

        public static void mergeSort(int[] arr) {
		if(arr == null || arr.length < 2) return;
		mergeSort(arr, 0, arr.length - 1);
		
	}

	public static void mergeSort(int[] arr, int l, int r) {
		//basecase 左右相等,就是只分到一个数了,就不用排了;
		if (l == r) {
			return;
		}
		int mid = l + ((r - l)>>1);
		mergeSort(arr, l, mid);
		mergeSort(arr, mid + 1, r);
		merge(arr, l, mid, r);
		
	}

	public static void merge(int[] arr, int l, int mid, int r) {
		int[] help = new int[(r - l + 1)];
		int i = 0;
		int p = l;
		int q = mid + 1;
		//能用while 不用for
		while(p <= mid && q <= r) {
			help[i++] = arr[p] < arr[q] ? arr[p++] : arr[q++];
		}
		while(p <= mid) {
			help[i++] = arr[p++];
		}
		while(q <= r) {
			help[i++] = arr[q++];
		}
		//一开始忘记把数组转回来了
		for (i = 0; i < help.length; i++) {
			arr[l + i] = help[i];
		}
	}

5、快排:思想:快排之所以叫快拍就因为它比较快,没有merge排序中merge过程,排完之后不需要调整。需要辅助

空间 每次划分需要两个,一共logN次划分。所以 时间复杂度为O(N*Log N),空间复杂度为 O(log N)。

       public static void quickSort(int[] arr) {
		if(arr == null || arr.length < 2) return;
		quickSort(arr, 0, arr.length - 1);
		
	}
	public static void quickSort(int[] arr, int l, int r) {
		//一开始这样做是不对if(l == r)return; 因为这不是basecase(暂时不懂,不过l < r更通用)
		if(l < r) {
			int[] p = partition(arr, l, r);
			quickSort(arr,l,p[0]-1);
			quickSort(arr,p[1]+1,r);
		}
		
	}

	
	private static int[] partition(int[] arr, int l, int r) {
		int less = l-1;
		//这里只能算个经验了,如果我用more = r + 1就会出现越界的情况
		int more = r;
		int num = arr[r];
		int cur = l;
		while(cur < more) {
			if(arr[cur] < num) {
				swap(arr,++less,cur++);
			}else if(arr[cur] > num) {
				swap(arr,cur,--more);
			}else {
				cur++;
			}
		}
		swap(arr,more,r);
		return new int[] {less+1,more};
	}
	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

6、堆排序:思想:大根堆 (任何一颗子树 根节点是最大节点的完成二叉树树 是 大根堆),插入大根堆,放在最后,与父节点比(i-1)/2,比父节点大就上升。把所有的节点放进了,这是最大就是根节点了,把根节点与最后一个节点交换 。

public static void heapSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			heapInsert(arr, i);
		}
		//这里选择arr.length而不是arr.length-1 只不过是一种优化代码方法
		//这是 根最大 将根与最后一个数交换 并排出,size就减1了,换上来的在在根本需要调整
		int size = arr.length;
		swap(arr, 0, --size);
		while (size > 0) {
			//重新调整为大根堆
			heapify(arr, 0, size);
			swap(arr, 0, --size);
			
		}
	}

	public static void heapInsert(int[] arr, int index) {
		while (arr[index] > arr[(index - 1) / 2]) {
			swap(arr, index, (index - 1) / 2);
			index = (index - 1) / 2;
		}
	}
	//0到size-1范围内形成了堆,index这个位置发生改变,然后进行调整。
	public static void heapify(int[] arr, int index, int heapSize) {
		int left = index * 2 + 1;
		while (left < heapSize) {
			//选择左右孩子 哪个个 保证右孩子不越界
			int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
			largest = arr[largest] > arr[index] ? largest : index;
			if (largest == index) {
				break;
			}
			swap(arr, largest, index);
			index = largest;
			left = index * 2 + 1;
		}
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

 7、桶排序、计数排序、基数排序都与数据有关。且时间复杂度O(N+C)

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值