算法
文章目录
一、排序
排序的稳定性和复杂度
稳定:
冒泡排序(bubble sort) — O(n2)
插入排序(insertion sort)— O(n2)
归并排序 (merge sort)— O(n log n); 需要 O(n) 额外存储空间
二叉树排序(Binary tree sort) — O(nlogn); 需要 O(n) 额外存储空间
计数排序 (counting sort) — O(n+k); 需要 O(n+k) 额外存储空间,k为序列中Max-Min+1
桶排序 (bucket sort)— O(n); 需要 O(k) 额外存储空间
不稳定:
选择排序(selection sort)— O(n2)
快速排序(quicksort)— O(nlogn) 平均时间, O(n2) 最坏情况; 对于大的、乱序串列一般认为是最快的已知排序
堆排序 (heapsort)— O(nlogn)
希尔排序 (shell sort)— O(nlogn)
基数排序(radix sort)— O(n·k); 需要 O(n) 额外存储空间 (K为特征个数)
- 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
- 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
冒泡排序
依次比较相邻的两个数,将小数放在前面,大数放在后面
public void function sortArray(int[] arr) {
for (int i = 0; i < arr.length-1;i++) {
for(int j = 0 ; j < arr.length-1;j++){
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
插入排序
将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据
private static void insertSort(int[] sort) {
for (int i = 1; i < sort.length; i++) {
int index = i - 1;
int temp = sort[i];
while (index >= 0 && sort[index] > temp) {
sort[index + 1] = sort[index];
index--;
}
sort[index + 1] = temp;
}
}
快速排序
- 首先区间采用以找到第一个数为基准数base,
- 从左向右,找到比base值大的值,从右至左,找到比base基准值小的值;替换这两个数,循环直到基准数base左边小右边大为止,返回最后一步索引;
- 以索引划分区间,递归;重复 第二步
private static void quickSort(int[] array ,int start, int end) {
if (start < end) {
int baseIndex = partition(array,start, end);// 分区操作,找到基准值,返回索引
if(start<baseIndex) {
quickSort(array,start, baseIndex);// 再次递归
}
if(baseIndex<end) {
quickSort(array,baseIndex + 1, end);// 再次递归
}
}
}
private static int partition(int[] array,int start, int end) {
int pivot = array[start];// 假设start位置的数是基准值
int i = start;
int j = end;
while (i < j) {
//从左向右,找到比base基准值大的值
while (array[i] < pivot) {
i++;
}
//从右至左,找到比base基准值小的值
while (array[j] > pivot) {
j--;
}
if (i < j) {
swap(array,i, j);
i++;j--;
}
}
return j;
}
//交换
private static void swap(int[] array,int i,int j){
int temp=array[i];
array[i]=array[j];
array[j]=temp;
}
二、查找算法
1、顺序查找
2、二分查找
//二分查找,递归版本
public class BinarySearch2{
//递归查找
public static int binarysearch(int[] a,int value,int low,int high){
int mid = (low + high)/2;
if(value == a[mid]){
return mid;
}else if(value < a[mid])
return binarysearch(a,value,low,mid - 1);
}else if(value > a[mid])
return binarysearch(a,value,mid + 1,high);
}
return -1;
}
//循环查找
public static int binarysearch(int[] a,int value){
int left=0;
int right=a.length-1;
int middle=0;
while(left<=right) {
middle=(left+right)/2;
if(value == a[middle]){
return middle;
}else if(value < a[middle]) {
left=middle - 1;
}else if(value > a[middle]) {
right=middle + 1;
}
}
return middle;
}
public static void main(String[] args) {
//int[] a = {1,4,2,9,8,6,7,0,3,5}
int[] a = {0,1,2,3,4,5,6,7,8,9};
System.out.println(binarysearch(a,4,0,a.length-1));
}
}
3、插值查找
4、斐波那契查找
5、树表查找
6、分块查找
7、哈希查找
三、常见算法题型
1、求阶乘
//求取n的阶乘
public int factorial(int n) {
if(n==1){
return 1;
}else{
return n*factorial(n-1);
}
}
2、斐波那契数列
//求取斐波那契数列1、1、2、3、5、8、13
private int print(int n) {
if(n==1||n==2){
return 1;
}else{
return print(n-1)+print(n-2);
}
}
3、验证回文数
//判断字符串从索引i 到 j 位置的字符串是否是回文数
private boolean print2(String s,int i,int j){
if(j<=i){
return true;
}else if(s.charAt(i)!=s.charAt(j)){
return false;
}else{
return print2(s,i+1,j-1);
}
}
四、树
树的度:树节点的子树的数量为结点的度
1、遍历树
遍历树四种基本的遍历思想为:
前序遍历:根结点 —> 左子树 —> 右子树
中序遍历:左子树—> 根结点 —> 右子树
后序遍历:左子树 —> 右子树 —> 根结点
层次遍历:仅仅需按层次遍历就可以
前序遍历:1 2 4 5 7 8 3 6
中序遍历:4 2 7 5 8 1 3 6
后序遍历:4 7 8 5 2 6 3 1
层次遍历:1 2 3 4 5 6 7 8
//采用递归方式:---->>>>>>>>>>>>>
//前序遍历
public void preOrderTraverse1(TreeNode root) {
if (root != null) {
System.out.print(root.val+" ");
preOrderTraverse1(root.left);
preOrderTraverse1(root.right);
}
}
//中序遍历
public void inOrderTraverse1(TreeNode root) {
if (root != null) {
inOrderTraverse1(root.left);
System.out.print(root.val+" ");
inOrderTraverse1(root.right);
}
}
//后续遍历
public void postOrderTraverse1(TreeNode root) {
if (root != null) {
postOrderTraverse1(root.left);
postOrderTraverse1(root.right);
System.out.print(root.val+" ");
}
}
//层次遍历
public void levelTraverse(TreeNode root) {
if (root == null) {
return;
}
LinkedList<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
System.out.print(node.val+" ");
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
五、队列
1、循环队列
import java.io.*;
public class QueueArray {
Object[] a; //对象数组,队列最多存储a.length-1个对象
int front; //队首下标
int rear; //队尾下标
public QueueArray(){
this(10); //调用其他构造方法
}
public QueueArray(int size){
a = new Object[size];
front = 0;
rear =0;
}
/**
* 将一个对象追加到队列尾部
* @param obj 对象
* @return 队列满时返回false,否则返回true
*/
public boolean enqueue(Object obj){
if((rear+1)%a.length==front){
return false;
}
a[rear]=obj;
rear = (rear+1)%a.length;
return true;
}
/**
* 队列头部的第一个对象出队
* @return 出队的对象,队列空时返回null
*/
public Object dequeue(){
if(rear==front){
return null;
}
Object obj = a[front];
front = (front+1)%a.length;
return obj;
}
public static void main(String[] args) {
QueueArray q = new QueueArray(4);
System.out.println(q.enqueue("张三"));
System.out.println(q.enqueue("李斯"));
System.out.println(q.enqueue("赵五"));
System.out.println(q.enqueue("王一"));//无法入队列,队列满
for(int i=0;i<4;i++){
System.out.println(q.dequeue());
}
}
}
六、加密算法
DES加密算法
AES加密算法
RSA加密算法:非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。RSA
Base64加密算法
MD5加密算法:消息摘要算法,不可逆
SHA1加密算法
摘要算法:MD5(128位)、SHA1(160位),是一种不可逆的过程,无论多大的数据,经过摘要算法后都生成相同长度的数据。只能通过字典进行破解。
对称加密算法:DES、AES,加密解密时使用相同的秘钥。
非对称加密算法:RSA,加密解密时使用不同的秘钥,对接支付宝使用RSA2。