数据结构基础算法整理

主要内容有:树的遍历(递归、非递归借助堆栈、非递归不借助堆栈);图的遍历;八大排序算法;二分查找

参考资料

java实现二分查找-两种方式

八大排序算法总结与java实现

  1. 树的遍历。可以分为:递归式、非递归借助栈式、非递归非借助栈式

    • 先序递归遍历 。先左后右是确定的,先中后序是对根节点而言,除了先后遍历无法确定二叉树的结构,其他都可以。

      public void preOrder(TreeNode root){
          if(root!=null){
              visit(root);
              preOrder(root.left);
              preOrder(root.right);
          }
      }
      
    • 中序递归遍历

      public void inOrder(TreeNode root){
          if(root!=null){
              preOrder(root.left);
              visit(root);
              preOrder(root.right);
          }
      }
      
    • 后序递归遍历

      public void postOrder(TreeNode root){
          if(root!=null){
              preOrder(root.left);
              preOrder(root.right);
              visit(root);
          }
      }
      
    • 先序、中序遍历,非递归借助栈

      public void preinOrder2(TreeNode root){
          if(root==null)
              return;
          Stack<TreeNode> s=new Stack<>();
          TreeNode p=root;
          while(p!=null||!s.isEmpty()){
              if(p!=null){
                  visit(p);	//这里访问顺序是先序
                  s.push(p);
                  p=p.left;
              }else{
                  p=s.pop();
                  visti(p);	//这里访问顺序是中序
                  p=p.right;
              }
          }
      }
      
    • 后序遍历,非递归借助栈

      public void postOrder2(TreeNode root){
          if(root==null)
              return;
          TreeNode cur=pre=null;
          Stack<TreeNode> s=new Stack<>();
          s.push(root);
          while(!s.isEmpty()){
              cur=s.peek();
              //两种情况
              //1.当前节点左右孩子都为空,那么可以进行访问
              //2.pre不为空,且其就是自己的左孩子或有孩子
              //3.第二点可能觉得有疑问:咋能说刚刚访问的是左孩子就可以访问当前节点了呢,关于这个看下面
              if(cur.left==null&&cur.right==null||
                 pre!=null&&(cur.left==pre||cur.right==pre)){
                  visit(cur);
                  pre=cur;
                  s.pop();
              }else{
                  //关于一个节点,若它有左右孩子,则其一定是连续入栈的,不会存在那种
                  //cur是当前根节点,它左孩子访问了,是pre;它右孩子还没访问的情况
                  if(cur.right!=null)
                      s.push(cur.right);//这里一定要先右后左,才能保证出栈先左后右
                  if(cur.left!=null)
                      s.push(cur.left);
              }
          }
      }
      
    • 先序遍历,非递归非借助栈 。中序、后序的就不写了

      public void preOrder3(TreeNode root){
          if(root==null)
              return;
          while(root.left!=null){
              visit(root);
              root=root.left;
          }
          visit(root);
          while(root!=null){
              if(root.right!=null){
                  root=root.right;
                  visit(root);
                  while(root.left!=null){
                      root=root.left;
                      visit(root);
                  }
              }else{
                  TreeNode temp=null;
                  do{
                      temp=root;
                      root=root.parent;
                  }while(root!=null&&temp==root.right)
              }
          }
      }
      
    • 层次遍历,借助队列

      public void levelOrder(TreeNode root){
          if(root==null)
              return;
          Queue<TreeNode> q=new Queue<>();
          TreeNode temp=root;
          q.push(temp);
          while(!q.isEmpty()){
              temp=q.pop();
              visit(temp);
              if(temp.left!=null)
                  q.push(temp.left);
              if(temp.right!=null)
                  q.push(temp.right);
          }
      }
      
  2. 图的遍历。这里只写DFS和BFS的伪代码

    • 深度优先遍历

      public void DFSTraverse(Graph G){
          //相当于初始化一个全为false的邻接矩阵,n为节点数
          boolean[] visited=new boolean[G.num*G.num];
          for(int i=0;i<G.num;i++){
              if(!visited[i])
                  DFS(G,i);
          }
      }
      
      private void DFS(Graph G, int i){
          visit(i);
          visited[i]=true;
          for(w=FirstNeighbor();w>0;w=NextNeighboe())
              if(!visited[w])
                  DFS(G,w);
      }
      
    • 广度优先遍历

      public void BFSTraverse(Graph G){
          //相当于初始化一个全为false的邻接矩阵,n为节点数
          boolean[] visited=new boolean[G.num*G.num];
          for(int i=0;i<G.num;i++){
              if(!visited[i])
                  BFS(G,i);
          }
      }
      
      private void BFS(Graph G, int i){
          visit(i);
          visited[i]=true;
          q.push(i);
          while(!q.isEmpty()){
              i=q.pop();
              for(w=FirstNeighbor();w>0;w=NextNeighboe())
                  if(!visited[w]){
                      visit(w);
                      visited[w]=true;
                      q.push(w);
                  }
                      
          }
      }
      
  3. 八大基本排序算法

    • 时空复杂度

      算法时间-最好时间-平均时间-最坏空间
      直接插入n1
      希尔///1
      冒泡n1
      快排nlognnlognlogn
      简单选择1
      堆排序nlognnlognnlogn1
      2-路归并nlognnlognnlognn
      基数排序d(n+k)d(n+k)d(n+kd)n+kd
    • 直接插入排序

      public static void insertionSort(int[] arr){
          for( int i = 1; i < arr.length; i++ ) {
              int temp = arr[i];    // 取出下一个元素,在已经排序的元素序列中从后向前扫描
              for( int j = i; j >= 0; j-- ) {
                  if( j > 0 && arr[j-1] > temp ) {
                      arr[j] = arr[j-1];   
                  } else {
                      // 将新元素插入到该位置后
                      arr[j] = temp;
                      break;
                  }
              }
          }
      }
      
    • 希尔排序

      public static void shellSort(int[] arr){
          for (int gap = arr.length / 2;; gap > 0; gap /= 2) { //从n/2开始,到1结束
              for(int i=gap+1;i<arr.lenght;i++){
                  if(arr[i]<arr[i-gap]){
                      int temp=arr[i];
                      for(int j=i-gap;j>=0&&temp<arr[j];j-=gap)
                          arr[j+gap]=arr[j];
                      arr[j+gap]=temp;
                  }
              }
          }
      }
      
    • 冒泡排序

      public static void bubbleSort(int[] arr){
          for (int i = 0; i<arr.length-1; i++) {      //外层循环移动游标
              boolean flag=false;
              for(int j = arr.length; j>i; j--){    //内层循环遍历游标及之后(或之前)的元
                  if(arr[j]<arr[j-1]){
                      int temp = arr[j];
                      arr[j] = arr[j+1];
                      arr[j+1] = temp;
                      flag=true;
                  }
              }
              if(!flag)
                  break;
          }
      }
      
    • 快速排序

      public void quickSort(int[] a){
          if(a.length==0||a.length==1||a==null)
              return;
          quickSort(a,0,a.length-1);
      }
      
      private void quickSort(int[] a, int low, int high){
          if(low<high){
              int temp=partition(a, low, high);
              quickSort(a, low ,temp-1);
              quickSort(a, temp+1,high);
          }
      }
      
      private int partition(int[] a, int low, int high){
          int temp=a[low];
          while(low<high){
              while(low<high&&a[high]>temp)  --high;
              a[low]=a[high];
              while(low<high&&a[low]<temp)  ++low;
              a[high]=a[low];
          }
          a[low]=temp;
          return low;
      }
      
    • 简单选择排序

      public static void selectSort(int[] arr){
          for(int i = 0; i < arr.length-1; i++){
              int min = i;
              for(int j = i+1; j < arr.length; j++){    //选出之后待排序中值最小的位置
                  if(arr[j] < arr[min]){
                      min = j;
                  }
              }
              if(min != i){
                  int temp = arr[min];      //交换操作
                  arr[min] = arr[i];
                  arr[i] = temp;
              }
          }
      }
      
    • 堆排序 (基于完全二叉树的顺序存储结构,下面是大根堆)

      public void BuildMaxHeap(int[] a){//这里默认下标从1开始,这样好些好理解
          for(int i=a.length/2;i>0;i--)
              AdjustDown(a,i,a.length);
      }
      
      private void AdjustDown(int[] a, int k, int len){
          int temp=a[k];
          for(int i=2*k;i<=len;i*=2){
              if(i<len&&a[i]<a[i+1])
                  i++;
              if(temp>a[i])  break;
              else{
                  a[k]=a[i];
                  k=i;
              }
          }
          a[k]=temp;
      }
      

      在这里插入图片描述

    • 2-路归并排序

      private int[] b;
      public void mergeSort(int[] a){
          if(a.length==0||a.length==1||a==null)
              return;
          b=new int[a.length];
          mergeSort(a, 0, a.length-1);
      }
      
      private void mergeSort(int[] a, int low, int high){
          if(low<high){
              int midlle=(low+high)/2;
              mergeSort(a,low,mid);
              mergeSort(a,mid+1,high);
              merge(a,low,mid,high);
          }
      }
      
      private void merge(int[] a, int low, int mid, int high){
          for(int i=low;i<=high;i++)
              b[i]=a[i];
          for(int i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){
              if(b[i]<b[j])
                  a[k]=b[i++];
              else
                  a[k]=b[j++];
          }
          while(i<=mid)  a[k++]=b[i++];
          while(j<=high)  a[k++]=b[j++];
      }
      
    • 基数排序

      //暂且放弃
      
  4. 查找算法。主要有二分查找、索引查找、哈希查找。这里只整理二分查找

    • 二分查找

      public static int commonBinarySearch(int[] arr,int key){
      		int low = 0;
      		int high = arr.length - 1;
      		int middle = 0;			//定义middle
      		
      		if(key < arr[low] || key > arr[high] || low > high){
      			return -1;				
      		}
      		
      		while(low <= high){
      			middle = (low + high) / 2;
      			if(arr[middle] > key){
      				//比关键字大则关键字在左区域
      				high = middle - 1;
      			}else if(arr[middle] < key){
      				//比关键字小则关键字在右区域
      				low = middle + 1;
      			}else{
      				return middle;
      			}
      		}
      		
      		return -1;		//最后仍然没有找到,则返回-1
      	}
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值