JAVA算法学习

285 阅读6分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

JAVA-算法大全

这学期老师把算法交完了,整理了一些最常用的算法,其实最主要的还是算法思想 算法思想有很多

第一部分:Java数据结构

要理解Java数据结构,必须能清楚何为数据结构?

数据结构:

  1. Data_Structure,它是储存数据的一种结构体,在此结构中储存一些数据,而这些数据之间有一定的关系。
  2. 而各数据元素之间的相互关系,又包括三个组成成分,数据的逻辑结构,数据的存储结构和数据运算结构。
  3. 而一个数据结构的设计过程分成抽象层、数据结构层和实现层。

数据结构在Java的语言体系中按逻辑结构可以分为两大类:线性数据结构和非线性数据结构。

一、Java数据结构之:线性数据结构

线性数据结构:常见的有一维数组,线性表,栈,队列,双队列,串。

1:一维数组

在Java里面常用的util有:String [],int [],ArrayList,Vector,CopyOnWriteArrayList等。及可以同过一维数组[]自己实现不同逻辑结构的Util类。而ArrayList封装了一些[]的基本操作方法。ArrayList和Vector的区别是:Vector是线程安全的,方法同步。CopyOnWriteArrayList也是线程安全的但效率要比Vector高很多。(PS:如果不懂出门右拐看另一篇chat)。

数组这种数据结构典型的操作方法,是根据下标进行操作的,所以insert的的时候可以根据下标插入到具体的某个位置,但是这个时候它后面的元素都得往后面移动一位。所以插入效率比较低,更新,删除效率也比较低,而查询效率非常高,查询效率时间复杂度是1。

2: 线性表

线性表是有序的储存结构、链式的储存结构。链表的物理储存空间是不连续的,链表的每一个节点都知道上一个节点、或者下一个节点是谁,通常用Node表示。常见的有顺序链表(LinkedList、Linked***),单项链表(里面只有Node类),双向链表(两个Node类),循环链表(多个Node类)等。

操作方法:插入效率比较高,插入的时候只需要改变节点的前后节点的连接即可。而查询效率就比较低了,如果实现的不好,需要整个链路找下去才能找到应该找的元素。所以常见的方法有:add(index,element),addFirst(element),addLast(element)。getFirst(),getLast(),get(element)等。

常见的Uitil有:LinkedList,LinkedMap等,而这两个JDK底层也做了N多优化,可以有效避免查询效率低的问题。当自己实现的时候需要注意。其实树形结构可以说是非线性的链式储存结构。

3: 栈Stack

栈,最主要的是要实现先进后出,后进先出的逻辑结构。来实现一些场景对逻辑顺序的要求。所以常用的方法有push(element)压栈,pop()出栈。

java.util.Stack。就实现了这用逻辑。而Java的Jvm里面也用的到了此种数据结构,就是线程栈,来保证当前线程的执行顺序。

4:队列

队列,队列是一种特殊的线性数据结构,队列只能允许在队头,队尾进行添加和查询等相关操作。队列又有单项有序队列,双向队列,阻塞队列等。

Queue这种数据结构注定了基本操作方法有:add(E e)加入队列,remove(),poll()等方法。

队列在Java语言环境中是使用频率相当高的数据结构,所有其实现的类也很多来满足不同场景。

1.冒泡排序

冒泡排序(Bubble Sort)它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。 这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。

实例

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数
  3. 针对所有的元素重复以上的步骤,除了最后一个
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

图片.png

非优化版本

代码

package test1;
import java.util.Arrays;
/**
 * @author 小徐同学
 *
 * 2022年04月02日
 */
public class BubbleSort {
	public static void bubbleSort(int arr[]) {
		 
        for(int i = 0 ; i < arr.length-1 ; i++) { 

            for(int j = 0 ; j < arr.length-1-i ; j++) {  
 
                if(arr[j] > arr[j+1]) {
                    int temp = arr[j];
                     
                    arr[j] = arr[j+1];
                     
                    arr[j+1] = temp;
            }
            }    
        }
    }
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int [] arr = {10,20,3,0,40,52,3,4};
		System.out.println("冒泡排序前:"+Arrays.toString(arr));
		
		bubbleSort(arr);
		System.out.println("冒泡排序后"+Arrays.toString(arr));

	}

}

结果

冒泡排序前:[10, 20, 3, 0, 40, 52, 3, 4] 冒泡排序后[0, 3, 3, 4, 10, 20, 40, 52]

优化版本

数据的顺序排好之后,冒泡算法仍然会继续进行下一轮的比较,直到arr.length-1次,后面的比较没有意义的。

方案:

设置标志位flag,如果发生了交换flag设置为true;如果没有交换就设置为false。 这样当一轮比较结束后如果flag仍为false,即:这一轮没有发生交换,说明数据的顺序已经排好,没有必要继续进行下去。

package test1;
import java.util.Arrays;
/**
 * @author 小徐同学
 *
 * 2022年04月02日
 */
public class BubbleSort {
	public static void BubbleSort1(int [] arr){
		  int temp;//临时变量
	  boolean flag;//是否交换的标志
		  for(int i=0; i<arr.length-1; i++){   //表示趟数,一共 arr.length-1 次      // 每次遍历标志位都要先置为false,才能判断后面的元素是否发生了交换
			   flag = false;
	     for(int j=arr.length-1; j>i; j--){ //选出该趟排序的最大值往后移动
         if(arr[j] < arr[j-1]){
          temp = arr[j];
         arr[j] = arr[j-1];

       arr[j-1] = temp;
               flag = true;    //只要有发生了交换,flag就置为true
	       }
   }
     // 判断标志位是否为false,如果为false,说明后面的元素已经有序,就直接return
      if(!flag) break ;}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int [] arr = {10,20,3,0,40,52,3,4};
		System.out.println("冒泡排序前:"+Arrays.toString(arr));
		
		BubbleSort1(arr);
		System.out.println("冒泡排序后"+Arrays.toString(arr));

	}

}

结果

冒泡排序前:[10, 20, 3, 0, 40, 52, 3, 4] 冒泡排序后[0, 3, 3, 4, 10, 20, 40, 52]