这些代码都有手写的可能性
1. 二分查找
/**
* @program: 必背算法
* @description: 二分查找的实现
* @author: huang xin
* @create: 2018-11-26 20:57
*/
/**
* 应用场景:在有序数组中查找某几个数字在数组中的位置
*
* 思路:利用数组的有序性,不需要逐个查找。只需要每次与数组中间元素比较
*
* 时间复杂度:O(logn)
* */
public class BinarySearch {
/**方法都声明为,类方法(public static)*/
/**
* @param arr 有序数组
* @param val 查找元素
* @return int 返回元素下标
* */
public static int binarySearch(int[] arr, int val){
int left = 0;
int right = arr.length-1;
int mid;
while (left <= right){
mid = (right - left)/2 + left;
if (val == arr[mid]){
return mid;
}else if (val > arr[mid]){
left = mid +1;
}else {
right = mid - 1;
}
}
return -1; //数组中没有该值,返回-1
}
/**mian用来测试上面的方法正确性*/
public static void main(String[] args) {
int[] arr = {2,5,6,7,8,11,14};
System.out.println(binarySearch(arr,11));
}
}
2. 冒泡排序
/**
* @program: 必背算法
* @description: 冒泡排序
* @author: huang xin
* @create: 2018-11-26 21:39
*/
/**
* 应用场景:给无序的数组排序
*
* 思路:依次比较相邻两个数,把大数安排在后面。当数组中只有一个数未排序时,数组就有序了
* 利用双重for循环,外层控制比较范围,内层控制比较元素
*
* */
public class BubbleSort {
/**
* @param arr 未排序数组
* @return int[] 已经排好序数组
* */
public static int[] bubbleSort(int[] arr){
for (int length = arr.length -1 ; length > 0 ;length--){ //此处注意java.lang.ArrayIndexOutOfBoundsException
for (int index = 0; index < length ;index ++){
if (arr[index] > arr[index+1]){ //比较相邻两个数
int temp = arr[index];
arr[index] = arr[index+1];
arr[index+1] = temp;
}
}
}
return arr;
}
public static void main(String[] args) {
int[] arr = {24,65,2,-7,8,24,654,};
bubbleSort(arr);
for (int a : arr){ //增强for遍历
System.out.print(a + ",");
}
}
}
注意改进的冒泡法
/**
* 对于基本有序的数组可以优化算法,例如:7 ,1,2,3,4,5
* 采用设置标志位,判断没有发生相邻两个元素交换就跳出循环
* */
public static int[] bubbleSort2(int[] arr){
boolean flag = true;
int length = arr.length -1;
while (flag){
flag = false; //本次内循环若无元素交换,则判定后面元素是有序的。不再进行排序
for (int j = 0 ;j < length; j ++){ //在length等于某个值时,遍历一次数组发现都是后面的数大。标志位为false退出外层循环。
if (arr[j] > arr[j+1]){ //一旦发生一次后面的数小,标志位就改变
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
flag = true;
}
}
length --;
}
return arr;
}
/**
* 还有一种情况:数据量很大,但只有前200是无序的,后面的有序且比前面的大
*
* 思路:找到前面无序和后面有序的分界点,即第一次全数组遍历发现后面前面数不大于后面数时。下次就只遍历到这个地方
* i是活动的表示前几个数还未排序
* */
public static int[] sort3(int[] arr){
int flag = arr.length -1;
while (flag > 0){
int k = flag; //k来记录遍历的尾边界
flag = 0;
for (int j = 0 ; j < k ; j ++){ //k在变化,内循环不用遍历所用,只遍历前面无序部分
if (arr[j] > arr[j+1]){ //没发生交换,代表已经有序了,flag在循环中没有赋值,外层默认为0 退出while
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
flag = j; //记录每次内循环的尾边界
}
}
}
return arr;
}
3、快排
这种排序思想,找了很多种代码实现方式。发现有一种可以理解
核心:partition加递归,使partition点的左边小,右边大。然后找中间区域新的partition,递归下去直到左边界大于右边界。
/**
* 关键是:如何写partition,后面直接递归
* */
public class QuickSort {
/**
* 返回partition的点,是之前元素小,之后元素大
*/
/**
* @param arr 待排序数组
* @param l, 区间左边界
* @param r ,区间右边界
* @return 标定点该在数组的位置
* */
public static int partition(int[] arr, int l, int r) {
//目的:遍历数组,把arr[l]安排到合适位置
int partition = arr[l];
int j = l; //维护区间 arr[l+1,j] < v ,arr[j+1 ,i) >v
for (int i = l + 1; i <= r; i++) { //i表示正在遍历的数,从第二个开始,
// 如果小于partition,与前面区间的末尾(j+1)交换
//若大于partition,当前遍历元素不变,遍历指针后移(i++)
if (arr[i] < partition) {
j++;
//交换arr[i] 与arr[j+1]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//结束循环后,将partition移到中间,即交换l与j的位置
int temp = arr[l];
arr[l] = arr[j];
arr[j] = temp;
return j; //返回
}
/**快排*/
public static void sort(int[] arr, int l, int r) {
if (l >= r) { //递归结束条件
return;
}
int p = partition(arr, l, r); //找标定点,对左右区间再进行排序
sort(arr, l, p - 1);
sort(arr, p + 1, r);
}
public static void main(String[] args) {
int[] arr2 = {789, 1, 654, 6, 8, 24, 3};
sort(arr2, 0, 6);
for (int a : arr2)
System.out.print(a + ",");
}
}
还要加树的遍历和链表的操作
4、二叉树的遍历
public class BinaryTree {
/**声明一棵树,它有一个值域,两个指针域*/
class Node{
public int data;
public Node left; //左子树
public Node right; //右子树
public Node(int date ,Node right ,Node left){
this.data =date;
this.right = right;
this.left = left;
}
}
/**采用递归遍历,前序、中序、后序*/
/**
* @param root 给定一个二叉树根节点
* */
public static void preOrder(Node root){
if (root != null){
System.out.print(root.data + ",");
preOrder(root.left);
preOrder(root.right);
}
}
/**
* @param root 传入数的根节点
* */
public static void middleOrder(Node root){
if (root != null){
middleOrder(root.left);
System.out.print(root.data + ",");
middleOrder(root.right);
}
}
public static void afterOrder(Node root){
if (root != null){
afterOrder(root.left);
afterOrder(root.right);
System.out.print(root.data + ",");
}
}
/**采用非递归方式遍历*/
/** 层序遍历:用队列实现
* 特点:先进的节点先出去,本质依次存入依次出队
* */
public static void levelOrder(Node root){
if (root == null)
return;
LinkedList<Node> linkedList = new LinkedList<>(); //创建队列
linkedList.offer(root); //头结点入队
while (!linkedList.isEmpty()){
Node node = linkedList.poll(); //出队,拿到对列的元素
System.out.println(node.data); //打印数据
//左右节点不为空,就要依次入队
if (node.left != null){
linkedList.offer(node.left);
}
if (node.right != null){
linkedList.offer(node.right);
}
}
}
/**非递归前序:用Stack模拟栈
* 注意:为了保证先打印左子树,需要右子树先入栈
* */
public static void noPreOrder(Node root){
Stack<Node> stack = new Stack<>(); //创建了一个栈
stack.push(root); //将树的头结点放入栈中
Node p = null; //定义一个节点的引用来指向出栈的节点
while (!stack.isEmpty()){ //栈不为空就可以出栈
p = stack.pop();
if (p != null){
System.out.println(p.data);
stack.push(p.right);
stack.push(p.left);
}
}
}
}