数据结构基础算法整理

数据结构基础算法整理

主要内容有:树的递归遍历、非递归借助栈遍历、非递归不借助栈遍历、层次遍历;图的深度优先遍历、广度优先遍历;八大排序算法:插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、2-路归并排序、基数排序;查找算法:二分查找

参考资料

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);
              }
          }
      }
      
    • 先序遍历,非递归非借助栈 。中序、后序的就不写了

      扫描二维码关注公众号,回复: 5592441 查看本文章
      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. 八大基本排序算法

    • 时空复杂度

      算法 时间-最好 时间-平均 时间-最坏 空间
      直接插入 n 1
      希尔 / / / 1
      冒泡 n 1
      快排 nlogn nlogn logn
      简单选择 1
      堆排序 nlogn nlogn nlogn 1
      2-路归并 nlogn nlogn nlogn n
      基数排序 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){
          int gap = arr.length / 2;
          for (; gap > 0; gap /= 2) {      //不断缩小gap,直到1为止
              for (int j = 0; (j+gap) < arr.length; j++){     //使用当前gap进行组内插入排序
                  for(int k = 0; (k+gap)< arr.length; k += gap){
                      if(arr[k] > arr[k+gap]) {
                          int temp = arr[k+gap];      //交换操作
                          arr[k+gap] = arr[k];
                          arr[k] = temp;
                          System.out.println("    Sorting:  " + Arrays.toString(arr));
                      }
                  }
              }
          }
      }
      
    • 冒泡排序

      public static void bubbleSort(int[] arr){
          for (int i = arr.length; i > 0; i--) {      //外层循环移动游标
              for(int j = 0; j < i && (j+1) < i; j++){    //内层循环遍历游标及之后(或之前)的元素
                  if(arr[j] > arr[j+1]){
                      int temp = arr[j];
                      arr[j] = arr[j+1];
                      arr[j+1] = temp;
                      System.out.println("Sorting: " + Arrays.toString(arr));
                  }
              }
          }
      }
      
    • 快速排序

      public static void quickSort(int[] arr, int low, int high){
          if(arr.length <= 0) return;
          if(low >= high) return;
          int left = low;
          int right = high;
      
          int temp = arr[left];   //挖坑1:保存基准的值
          while (left < right){
              //坑2:从后向前找到比基准小的元素,插入到基准位置坑1中
              while(left < right && arr[right] >= temp){  
                  right--;
              }
              arr[left] = arr[right];
              //坑3:从前往后找到比基准大的元素,放到刚才挖的坑2中
              while(left < right && arr[left] <= temp){   
                  left++;
              }
              arr[right] = arr[left];
          }
          arr[left] = temp;   //基准值填补到坑3中,准备分治递归快排
          System.out.println("Sorting: " + Arrays.toString(arr));
          quickSort(arr, low, left-1);
          quickSort(arr, left+1, high);
      }
      
    • 简单选择排序

      public static void selectionSort(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;
                  System.out.println("Sorting:  " + Arrays.toString(arr));
              }
          }
      }
      
    • 堆排序

      public static void heapSort(int[] arr){
          for(int i = arr.length; i > 0; i--){
              max_heapify(arr, i);
      
              int temp = arr[0];      //堆顶元素(第一个元素)与Kn交换
              arr[0] = arr[i-1];
              arr[i-1] = temp;
          }
      }
      
      private static void max_heapify(int[] arr, int limit){
          if(arr.length <= 0 || arr.length < limit) return;
          int parentIdx = limit / 2;
      
          for(; parentIdx >= 0; parentIdx--){
              if(parentIdx * 2 >= limit){
                  continue;
              }
              int left = parentIdx * 2;       //左子节点位置
              //右子节点位置,如果没有右节点,默认为左节点位置
              int right = (left + 1) >= limit ? left : (left + 1);    
      
              int maxChildId = arr[left] >= arr[right] ? left : right;
              if(arr[maxChildId] > arr[parentIdx]){   //交换父节点与左右子节点中的最大值
                  int temp = arr[parentIdx];
                  arr[parentIdx] = arr[maxChildId];
                  arr[maxChildId] = temp;
              }
          }
          System.out.println("Max_Heapify: " + Arrays.toString(arr));
      }
      
    • 2-路归并排序

      public static int[] mergingSort(int[] arr){
          if(arr.length <= 1) return arr;
      
          int num = arr.length >> 1;
          int[] leftArr = Arrays.copyOfRange(arr, 0, num);
          int[] rightArr = Arrays.copyOfRange(arr, num, arr.length);
          System.out.println("split two array: " + Arrays.toString(leftArr) + " And " + Arrays.toString(rightArr));
          return mergeTwoArray(mergingSort(leftArr), mergingSort(rightArr));      //不断拆分为最小单元,再排序合并
      }
      
      private static int[] mergeTwoArray(int[] arr1, int[] arr2){
          int i = 0, j = 0, k = 0;
          int[] result = new int[arr1.length + arr2.length];  //申请额外的空间存储合并之后的数组
          while(i < arr1.length && j < arr2.length){      //选取两个序列中的较小值放入新数组
              if(arr1[i] <= arr2[j]){
                  result[k++] = arr1[i++];
              }else{
                  result[k++] = arr2[j++];
              }
          }
          while(i < arr1.length){     //序列1中多余的元素移入新数组
              result[k++] = arr1[i++];
          }
          while(j < arr2.length){     //序列2中多余的元素移入新数组
              result[k++] = arr2[j++];
          }
          System.out.println("Merging: " + Arrays.toString(result));
          return result;
      }
      
    • 基数排序

      public static void radixSort(int[] arr){
          if(arr.length <= 1) return;
      
          //取得数组中的最大数,并取得位数
          int max = 0;
          for(int i = 0; i < arr.length; i++){
              if(max < arr[i]){
                  max = arr[i];
              }
          }
          int maxDigit = 1;
          while(max / 10 > 0){
              maxDigit++;
              max = max / 10;
          }
          System.out.println("maxDigit: " + maxDigit);
      
          //申请一个桶空间
          int[][] buckets = new int[10][arr.length];
          int base = 10;
      
          //从低位到高位,对每一位遍历,将所有元素分配到桶中
          for(int i = 0; i < maxDigit; i++){
              int[] bktLen = new int[10];        //存储各个桶中存储元素的数量
              
              //分配:将所有元素分配到桶中
              for(int j = 0; j < arr.length; j++){
                  int whichBucket = (arr[j] % base) / (base / 10);
                  buckets[whichBucket][bktLen[whichBucket]] = arr[j];
                  bktLen[whichBucket]++;
              }
      
              //收集:将不同桶里数据挨个捞出来,为下一轮高位排序做准备,
              //由于靠近桶底的元素排名靠前,因此从桶底先捞
              int k = 0;
              for(int b = 0; b < buckets.length; b++){
                  for(int p = 0; p < bktLen[b]; p++){
                      arr[k++] = buckets[b][p];
                  }
              }
      
              System.out.println("Sorting: " + Arrays.toString(arr));
              base *= 10;
          }
      }
      
  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
      	}
      

猜你喜欢

转载自blog.csdn.net/Saltwind/article/details/88635422
今日推荐