排序
插入排序:平均o(n2) 最好o(n)(有序)
//插入
public static void insertsort(int[] A){
for(int i = 1; i<A.length; i++){
int temp = A[i];
int j = i-1;
while(j>=0 && A[j]>temp){
A[j+1] = A[j];
j--;
}
A[j+1] = temp;
}
}
选择排序:o(n2)
//选择排序,将数组分为两部分,一部分为排序好的,一部分为未排序的,首先把最小的放最前面
public static void selsort(int[] A){
for(int i = 0; i < A.length-1; i++){
int l = i;
for(int j = i+1; j<A.length; j++){
if(A[l] > A[j]){
l = j;
}
}
if(l != i){
int temp = A[l];
A[l] = A[i];
A[i] = temp;
}
}
}
冒泡排序:o(n2)
//冒泡
public static void bubsort(int[] A){
for(int i = 0; i<A.length-1; i++){
for(int j = 0; j<A.length-1-i; j++){//第一大的挪到最后一位,第二大挪到倒数第二位
if(A[j]>A[j+1]){
int temp = A[j];
A[j] = A[j+1];
A[j+1] = temp;
}
}
}
}
堆排序(用的是数组):o(nlogn)整堆,最大堆,排序三步
//堆排序
public static void heapsort(int[] a){
if(a == null || a.length<=1){
return;
}
buildheap(a);
for(int i = a.length-1; i>=1; i--){
int temp = a[0];
a[0] = a[i];
a[i] = temp;
maxheap(a, i, 0);//注意,此处为i,不能把后面最大的再放上去了
}
}
//建最大堆
public static void buildheap(int[] a){
if(a == null || a.length<=1){
return;
}
int half = a.length/2;
for(int i = half; i>=0; i--){
maxheap(a, a.length, i);
}
}
//某个index往下落到最小的位置,大的放上来
public static void maxheap(int[] a, int heapsize, int index){
int left = index*2+1;
int right = index*2+2;
int largest = index;
if(left<heapsize && a[left]>a[index]){
largest = left;
}
if(right<heapsize && a[right]>a[largest]){
largest = right;
}
if(index != largest){
int temp = a[largest];
a[largest] = a[index];
a[index] = temp;
maxheap(a, heapsize, largest);
}
}
快排:平均o(nlogn)最差o(n2)(有序)
//快排
public static void quicksort(int[] A, int low, int high){
if(low < high){
int mid = partition(A,low,high);
quicksort(A, low, mid-1);
quicksort(A, mid+1, high);
}
}
public static int partition(int[] A, int low, int high){
int x = A[high];
int i = low-1;
for(int j = low; j<high; j++){
if(A[j] <= x){
int temp = A[j];
A[i+1] = temp;
A[j] = A[i+1];
i++;
}
}
++i;
int temp = A[i];
A[i] = x;
A[high] = temp;
return i;
}
归并排序:o(nlogn)递归+merge merge是用来合并两个有序数组
//归并排序
public static void mergesort(int[] A, int low, int high){
if(low<high){
int mid = (low+high) / 2;
mergesort(A, low, mid);
mergesort(A, mid+1, high);
merge(A, low, high, mid);
}
}
public static void merge(int[] A, int low, int high, int mid){
int[] m = new int[mid-low+1];
int[] n = new int[high-mid];
for(int i = 0; i<m.length; i++){
m[i] = A[i+low];
}
for(int j = 0; j<n.length; j++){
n[j] = A[mid+j+1];
}
int i = 0;
int j = 0;
int k = low;
while(i<m.length && j<n.length){
if(m[i]>n[j]){
A[k++] = n[j++];
}else{
A[k++] = m[i++];
}
}
while(i<m.length){
A[k++] = m[i++];
}
while(j<n.length){
A[k++] = n[j++];
}
}
查找
链表查找o(n),插入o(1);数组查找o(1),插入o(n)。
对于有序的数组(不能是链表,链表需要一个一个的next引用),可以用折半查找o(nlogn),有递归和非递归两种方式。
查找top10大的数,可以维护一个大小为10的最大堆。
对于数据量多的,可以用哈希,能在o(1)情况下查到(其实就是哈希索引),也可以建立索引。
对于查找大小为n-1的数组中(每个值不同,在1~n中,等于漏一个),可以用位图法,等于是new一个bool型的数组,因为bool型只占1个位,而一个int占4字节(4*8=32位),大小为1/32,而且在o(n)解决了问题。思想其实是哈希,以数的值作为bool数组的下表。(好多类似问题)
哈希的概念:将一个对象通过一种哈希函数,哈希成一个数值,这个数值是数组的下标,而数组里存放的即为这个对象,这就是建哈希表的过程。如果要查找,其实就是上面过程一样。
解决哈希冲突:链地址法,再哈希法,再散列法,公共溢出块等。
数据结构
数组
链表(双向链表的插入、删除)
堆
栈
树:树的插入,删除,先中后序(递归非递归),查找,各种树的算法,红黑树的一些概念。
层次遍历
之字形层次遍历
层次遍历改编 打印某一层
二叉树的下一结点(有无父亲指针)
是否为bst树
二叉树的平衡检查
二叉树和为某一值的路径 如果有返回值 则return 递归
树是否对称
两树是否相同
树的3种遍历的迭代算法
根据前中构建后
根据中后构建前
某数组是不是某bst树的后续遍历
二叉搜索树改双向链表 ······
可以去牛客上多练练
//先序遍历非递归
public static void preorder(TreeNode root){
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
while(node != null || !stack.isEmpty()){
//将所有的左孩子进栈
if(node != null){
//先访问再进栈
System.out.println(root.val);
stack.push(node);
node = node.left;
}else{
//到左下角空了先不急着回去,访问最左下角的右孩子
node = stack.pop();
node = node.right;
}
}
}
//中序遍历非递归
public static void inorder(TreeNode root){
TreeNode node = root;
Stack<TreeNode> stack = new Stack<>();
while(node!=null || !stack.isEmpty()){
if(node!=null){
stack.push(node);
node = node.left;
}else{
node = stack.pop();
System.out.println(node.val);
node = node.right;
}
}
}
//后续遍历非递归,需要再用一个辅助栈帮助存储后续遍历的结果
public static void postorder(TreeNode root){
TreeNode node = root;
Stack<TreeNode> stack = new Stack<>();
Stack<TreeNode> result = new Stack<>();
while(node!=null || !stack.isEmpty()){
if(node != null){
result.push(node);
stack.push(node);
node = node.right;
}else{
node = stack.pop();
node = node.left;
}
}
while(!result.isEmpty()){
System.out.println(result.pop().val);
}
}
图:最小生成树的prim和kruscal算法描述(两个思想都是贪心)。dijkstra(贪心在于用一个最小优先队列(即最小堆)维护剩余点,从剩余点选出)描述。哈夫曼描述(贪心)。