一、排序
1.选择排序
思路:每次选择最小的跟数组的第一个元素进行交换
public class SelectSort {
public void selectSort(int[] nums){
for(int i=0;i<nums.length;i++){
int index=i;
for(int j=i+1;j<nums.length;j++){
if(nums[j]<nums[index]){
index=j;
}
}
int t=nums[index];
nums[index]=nums[i];
nums[i]=t;
}
}
}
2.冒泡排序
每两个元素进行对比,大的元素放到后面,类似冒泡的过程
public class BubbleSort {
public void bubbleSort(int[] nums){
boolean flag=true;
for(int i=0;i<nums.length;i++){
for(int j=1;j<nums.length-i;j++){
if(nums[j-1]>nums[j]){
int t=nums[j-1];
nums[j-1]=nums[j];
nums[j]=t;
flag=false;
}
}
if(flag)break;
}
}
}
最坏情况是把顺序的排列变成逆序,或者把逆序的数列变成顺序。在这种情况下,每一次比较都需要进行交换运算。
3.插入排序
从未排序的元素中依次插入到已排序的队列中。
public void insertSort(int[] nums){
for(int i=1;i<nums.length;i++){
int ele=nums[i];
int j;
for(j=i;j>0&&nums[j-1]>ele;j--){
nums[j]=nums[j-1];
}
nums[j]=ele;
}
}
4.堆排序
先建立一个大顶堆,按照向下过滤的方式,然后将堆顶元素依次与堆的最后一个元素进行换位,再将新堆从根结点开始向下调整
public class HeapSort {
public void adjust(int[] nums,int i,int n){
int child=i;
int tmp;
for(tmp=nums[i];(2*i+1)<n;i=child){
child=2*i+1;
if(child+1<n&&nums[child]<nums[child+1]){
child++;
}
if(nums[child]>tmp){
nums[i]=nums[child];
}
else break;
}
nums[i]=tmp;
}
public void heapSort(int[] nums){
int n=nums.length;
for(int i=(n-1)/2;i>=0;i--){
adjust(nums,i,n);
}
for(int i=n-1;i>0;i--){
int tmp=nums[0];
nums[0]=nums[i];
nums[i]=tmp;
adjust(nums,0,i);
}
}
}
5.归并排序
申请额外的空间存放两个子序列归并之后的结果,设置两个指针分别指向两个已经排好序的元素的第一个位置,然后比较两个元素,将较小的元素放入到已经申请的额外的空间中并将位置向后移动一格
public class MergeSort {
public void merge(int[] nums,int[] tmp,int s,int e){
int left=s;
int mid=(s+e)/2+1;
int right=mid;
int index=s;
while(left<mid&&right<e){
if(nums[left]<nums[right]){
tmp[index++]=nums[left++];
}else{
tmp[index++]=nums[right++];
}
}
while(left<mid){
tmp[index++]=nums[left++];
}
while(right<e){
tmp[index++]=nums[right++];
}
for(int i=s;i<e;i++){
nums[i]=tmp[i];
}
}
public void mergeSort(int[] nums,int s,int e){
if(s<e) {
mergeSort(nums, 0, (s + e) / 2);
mergeSort(nums, (s + e) / 2+1, e);
int[] tmp = new int[nums.length];
merge(nums, tmp, s, e);
}
}
}
6.快速排序
快速排序,选取一个基准,先把它放到最右边,两个指针,分别从左到右,从右向左, 如果大就交换,一直到low>high,交换相应的位置和基准
public class QuickSort {
public void swap(int[] nums,int a,int b){
int t=nums[a];
nums[a]=nums[b];
nums[b]=t;
}
public void qsort(int[] nums,int s,int e){
int pivot=nums[s];
if(s>=e)return;
int left=s;
int right=e;
swap(nums,s,e);
while(true){
while(left<right&&nums[left]<=pivot)left++;
while(left<right&&nums[right]>=pivot)right--;
if(left>=right)break;
swap(nums,left,right);
}
swap(nums,left,e);
qsort(nums,s,left-1);
qsort(nums,left+1,e);
}
public void quickSort(int[] nums){
qsort(nums,0,nums.length-1);
}
}
快排的最坏情况
1)数组已经是正序(same order)排过序的。
2)数组已经是倒序排过序的。
3)所有的元素都相同(1、2的特殊情况)
通过要么选择一个随机的枢轴,或者选择一个分区中间的下标作为枢轴,或者(特别是对于相比更长的分区)选择分区的第一个、中间、最后一个元素的中值作为枢轴。
二、树
树的先序、中序遍历的递归比较简单,不再赘述。
树的先序遍历非递归实现
对于任一结点P:
1)将结点p压入栈中;
2)如果p有右孩子,将右孩子压入栈中;如果p有左孩子,将左孩子压入栈中;(注意先右孩子入栈,后左孩子入栈,这样可以先对左孩子进行后续操作)
3)将栈顶元素弹出(p的左孩子:q),访问,将q的右孩子,左孩子压入栈中,相当于回到第2步了。
4)直到stack.isEmpty == true,则遍历结束,否则回到第2步。
public static void preOrder(TreeNode root){
if(root==null)return;
Stack<TreeNode> s=new Stack<TreeNode>();
s.add(root);
while(s.isEmpty()==false){
TreeNode cur=s.pop();
System.out.print(cur.val+" ");
if(cur.right!=null)s.add(cur.right);
if(cur.left!=null)s.add(cur.left);
}
}
树的中序遍历
遇到一个节点,就把它入栈,并去遍历他的左子树,当左子树遍历结束后,就从栈顶弹出这个节点并访问他,然后按照右指针遍历右子树。
public static void inOrder(TreeNode root){
if(root==null)return;
Stack<TreeNode> s=new Stack<TreeNode>();
TreeNode cur=root;
while(cur!=null||!s.isEmpty()){
while(cur!=null){
s.add(cur);
cur=cur.left;
}
cur=s.pop();
System.out.print(cur.val+" ");
cur=cur.right;
}
}
树的后序遍历
利用一个辅助栈,最后逆转
左右根 -> 变换:先获得根右左的遍历顺序,再反转( 根右左的顺序可以通过栈即可实现)
public static void postOrder(TreeNode root){
if(root==null)return;
Stack<TreeNode> s=new Stack<TreeNode>();
Stack<Integer> reverse=new Stack<>();
s.add(root);
while(!s.isEmpty()){
TreeNode cur=s.pop();
reverse.add(cur.val);
if(cur.left!=null)s.add(cur.left);
if(cur.right!=null)s.add(cur.right);
}
while(!reverse.isEmpty()){
System.out.println(reverse.pop());
}
}
树的层序遍历
public static void levelOrder(TreeNode root){
Queue<TreeNode> que=new LinkedList<>();
que.add(root);
while(!que.isEmpty()){
TreeNode s=que.poll();
System.out.println(s.val);
if(s.left!=null)((LinkedList<TreeNode>) que).add(s.left);
if(s.right!=null)((LinkedList<TreeNode>) que).add(s.right);
}
}
三、二分查找
public static int binary(int[] nums,int left,int right,int s){
if(left>=right)return -1;
int mid=(left+right)/2;
if(nums[mid]==s)return mid;
else if(nums[mid]<s){
return binary(nums,mid+1,right,s);
}else{
return binary(nums,left,mid,s);
}
}
四、反转链表
public static ListNode reverseList(ListNode ll){
ListNode cur=null,head=ll;
while(head!=null){
ListNode n=head.next;
head.next=cur;
cur=head;
head=n;
}
return cur;
}
五、遍历所有文件
public void list(File directory){
if(!(directory.exists()&&directory.isDirectory())){
throw new RuntimeException("根目录不存在");
}
File[] files=new File[];
for(File file:files){
System.out.println(file.getPath()+file.getName());
if(file.isDirectory()){
list(file);
}
}
}
六、红黑树
是一种自平衡的二叉查找树
- 节点是红色或黑色
- 根结点是黑色
- 每个叶子节点都是黑色的空节点
- 每个红色节点的两个子结点都是黑色,从每个叶子节点到根的所有路径上不能有两个连续的红色节点
- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
B-树
- 每个结点最多有m-1个关键字
- 根结点最少可以只有一个关键字
- 非根结点至少有Math.ceil(m/2)-1个关键字
- 每个结点中的关键字都按照从小到大的顺序排列,每个关键字的左子树中所有关键字都小于它,而右子树中的所有关键字都大于它。
- 所有叶子节点都位于同一层。
B+树
- 根结点最少有一个关键字
- B+树内部不保存数据,只用于索引,所有数据都存在叶子节点。
- m阶B+树表示内部最多有m-1个关键字,阶数m同时限制了叶子节点最多存储m-1个记录
- 内部节点中的key都按照从小到大的顺序排列。
- 每个叶子节点都存有相邻叶子节点的指针,叶子节点本身是按照关键字的大小自小而大顺序连接。