2.算法与数据结构

news2024/11/6 7:09:33

算法与数据结构

文章目录

  • 算法与数据结构
    • 一、算法相关
      • 1、十大排序算法总结
        • 冒泡排序
        • 插入排序
        • 选择排序
        • 快速排序
        • 基数排序
        • 桶排序
        • 希尔排序
        • 归并排序
        • 堆排序
      • 2、经典算法介绍
        • 递归算法
        • 回溯算法
        • 贪心算法
        • 深度优先遍历
        • 广度优先遍历
        • 动态规划算法
      • 3、常见算法
        • 1、迪杰斯特拉(Dijkstra)算法介绍
    • 二、数据结构介绍
      • 1、字符串
      • 2、数组
      • 3、链表
      • 4、Hash
      • 5、跳跃表
      • 6、二叉树
      • 7、大顶堆
      • 8、小顶堆
      • 9、红黑树
      • 10、B树
      • 11、B+树
      • 12、Treap树
      • 13、LSM树
      • 14、Trie树
      • 15、多叉树
      • 16、无向图
      • 17、有向图
      • 18、带权图(网)
      • 7、大顶堆
      • 8、小顶堆
      • 9、红黑树
      • 10、B树
      • 11、B+树
      • 12、Treap树
      • 13、LSM树
      • 14、Trie树
      • 15、多叉树
      • 16、无向图
      • 17、有向图
      • 18、带权图(网)

一、算法相关

1、十大排序算法总结

排序算法平均时间最差时间稳定度额外空间备注
冒泡排序O(n²)O(n²)稳定O(1)n小较好
插入排序O(n²)O(n²)稳定O(1)n小较好
选择排序O(n²)O(n²)不稳定O(1)n小较好
交换排序O(n²)O(n²)不稳定O(1)大部分数据已经排序好
快速排序O(nlogn)O(n²)不稳定O(nlogn)n大时较好
基数排序O(nlogrn)O(nlogrn)稳定O(n)n是真数,r是基数
桶排序O(nlogn)O(nlogn)不稳定O(n)数据均匀分配到每一个桶中快;
计数排序稳定O(n)
希尔排序O(nlogn)O(n²)1<s<2不稳定O(1)s是所选分组
归并排序O(nlogn)O(nlogn)稳定O(1)n大时候较好
堆排序O(nlogn)O(nlogn)不稳定O(1)n大时候较好

冒泡排序

冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。

public class BucketSort {
	public static void main(String[] args) {
		int[] arrays = {6,3,7,1000,1,3};
		
		for(int i=1;i<arrays.length;i++) {
			for(int k=0;k<arrays.length-1;k++) {
                
				if(arrays[k]>arrays[k+1]) {
					int tempNum = arrays[k];
					arrays[k] = arrays[k+1];
					arrays[k+1] = tempNum;
				}
			}
		}
	} 
	
	public static void print(int[] arrays) {
		for(int k=0;k<arrays.length;k++) {
			System.out.print(arrays[k]+",");
		}
		
	}
}

img

插入排序

插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入。

/**
 * 插入排序: 解题思路分布发
 * 思想: 先选一个稳定值, 数组其他值和稳定值做比较
 * 完成度:已完成
 * */
public class InsertSort {
	public static void main(String[] args) {
		int[] arrays = {6,3,7,1000,1,3};
		
		///1、第一次插入,期望结果:{3,6  ,7,1000,1,3};
		for(int j = 1;j<arrays.length;j++) { 
			for(int i = 0;i<j;i++) {
				if(arrays[j]<=arrays[i]) {
					int tempNum = arrays[i];
					arrays[i] = arrays[j];
					arrays[j] = tempNum;
				}
			}
			System.out.println("第"+j+"次找最小值:");
			System.out.println(Arrays.toString(arrays));
		}
	}
}

img

选择排序

选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。

img

  • 交换排序:

    快速排序

    快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n²) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。

    快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高!它是处理大数据最快的排序算法之一了。虽然 Worst Case 的时间复杂度达到了 O(n²),但是人家就是优秀,在大多数情况下都比平均时间复杂度为 O(n logn) 的排序算法表现要更好,可是这是为什么呢,我也不知道。好在我的强迫症又犯了,查了 N 多资料终于在《算法艺术与信息学竞赛》

    上找到了满意的答案

    快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。
    但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,
    比复杂度稳定等于 O(nlogn) 的归并排序要小很多。
    所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。
    

    1、算法步骤

    先从数列中取出一个数作为基准数。
    分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
    再对左右区间重复第二步,直到各区间只有一个数。
    
    /**
     * 描述:快速排序
     * 完成度:已完成
     * 时间复杂度:
     * 空间复杂度:
     * 
     * 排序思想:快速排序(Quicksort)是对冒泡排序的一种改进。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,
     *     其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
     * */
    public class QuickSort {
    
    	public static void main(String[] args) { 
    		int[] nums = {5,1,1,2,0,0};
    		
    		int[] arr = new int[8000000];
    		for (int i = 0; i < 8000000; i++) {
    			arr[i] = (int) (Math.random() * 8000000); // 生成一个[0, 8000000) 数
    		}
    		
    		long s1 = System.currentTimeMillis();
    		new QuickSort().sortArray(arr);
    		long s2 = System.currentTimeMillis();
    		System.out.println("快排耗时:"+(s2-s1));
    	}
    	
        public int[] sortArray(int[] nums) {
        	nums = quickSort(nums,0, nums.length-1);
    		return nums;
        }
        
        public int[] quickSort(int[] nums,int left, int right) {
        	
        	//初始化l,r
        	int l = left;
        	int r = right;
        	
        	//左右端值交换中间变量
        	int tempVal =0;
        	//中间节点
        	int pivot = nums[(left+right)/2];
        	
        	//左右2端往中心遍历
        	while (l<r) { 
        		//左边往右遍历
            	while (nums[l]<pivot) { 
        			l++;
        		}
            	
        		//右边往左遍历
            	while (nums[r]>pivot) { 
        			r--;
        		}
            	
            	//当左右2端点相交,说明完成一次值交换
            	if(l>=r) {
            		break;
            	}
            	
            	tempVal = nums[l];
            	nums[l] =  nums[r];
            	nums[r] = tempVal;
            	
            	//左边等于pivot,r后移
            	if(nums[l]==pivot) {
            		r--;
            	}
            	
            	//右边等于pivot,l后移
            	if(nums[r]==pivot) {
            		l++;
            	}
    		}
        	
        	//防止栈溢出,当l=r条件恒成立
        	if(l==r) {
        		l++;
        		r--;
        	}
        	
        	//左向右边递归
        	if(left<r) {
        		quickSort(nums,left, r);
        	}
        	
        	//右向左边递归
        	if(right>r) {
        		quickSort(nums,l, right);
        	}
    		return nums;
        }
    }
    

    基数排序

    基数排序(桶排序)介绍:基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,达到排序的作用基数排序法是属于稳定性的排序,基数排序法的是效率高的稳定性排序法基数排序(Radix Sort)是桶排序的扩展基数排序是1887年赫尔曼·何乐礼发明的。它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较。

    基数排序基本思想

    将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。这样说明,比较难理解,下面我们看一个图文解释,理解基数排序的步骤,将数组 {53, 3, 542, 748, 14, 214} 使用基数排序, 进行升序排序。

    ![1684744709980](C:\Users\hp\Documents\WeChat Files\god8816\FileStorage\Temp\1684744709980.png)

    ![1684744731546](C:\Users\hp\Documents\WeChat Files\god8816\FileStorage\Temp\1684744731546.png)

    ![1684744753790](C:\Users\hp\Documents\WeChat Files\god8816\FileStorage\Temp\1684744753790.png)

    /**
     * 基数排序
     * 完成度:已完成
     * 未理解
     * */
    public class RadixSort {
    
    	public static void main(String[] args) {
    		int arr[] = { 53, 3, 542, 748, 14, 214};
    		
    		// 80000000 * 11 * 4 / 1024 / 1024 / 1024 =3.3G 
    //		int[] arr = new int[8000000];
    //		for (int i = 0; i < 8000000; i++) {
    //			arr[i] = (int) (Math.random() * 8000000); // 生成一个[0, 8000000) 数
    //		}
    		System.out.println("排序前");
    		Date data1 = new Date();
    		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		String date1Str = simpleDateFormat.format(data1);
    		System.out.println("排序前的时间是=" + date1Str);
    		
    		radixSort(arr);
    		
    		Date data2 = new Date();
    		String date2Str = simpleDateFormat.format(data2);
    		System.out.println("排序前的时间是=" + date2Str);
    		
    		System.out.println("基数排序后 " + Arrays.toString(arr));
    		
    	}
    
    	//基数排序方法
    	public static void radixSort(int[] arr) {
    		
    		//根据前面的推导过程,我们可以得到最终的基数排序代码
    		
    		//1. 得到数组中最大的数的位数
    		int max = arr[0]; //假设第一数就是最大数
    		for(int i = 1; i < arr.length; i++) {
    			max = Math.max(max, arr[i]);
    		}
    		//得到最大数是几位数
    		int maxLength = (max + "").length();
    		
    		
    		//定义一个二维数组,表示10个桶, 每个桶就是一个一维数组
    		//说明
    		//1. 二维数组包含10个一维数组
    		//2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arr.length
    		//3. 名明确,基数排序是使用空间换时间的经典算法
    		int buckeNum = 10;
    		int[][] bucket = new int[buckeNum][arr.length];
    		
    		//为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数
    		//可以这里理解
    		//比如:bucketElementCounts[0] , 记录的就是  bucket[0] 桶的放入数据个数
    		int[] bucketElementCounts = new int[buckeNum];
    		
    		
    		//这里我们使用循环将代码处理
    		for(int i = 0 , n = 1; i < maxLength; i++, n *= buckeNum) {
    			//(针对每个元素的对应位进行排序处理), 第一次是个位,第二次是十位,第三次是百位..
    			for(int j = 0; j < arr.length; j++) {
    				//取出每个元素的对应位的值
    				int digitOfElement = arr[j] / n % buckeNum;
    				//放入到对应的桶中
    				bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
    				bucketElementCounts[digitOfElement]++;
    			}
    			//按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
    			int index = 0;
    			//遍历每一桶,并将桶中是数据,放入到原数组
    			for(int k = 0; k < bucketElementCounts.length; k++) {
    				//如果桶中,有数据,我们才放入到原数组
    				if(bucketElementCounts[k] != 0) {
    					//循环该桶即第k个桶(即第k个一维数组), 放入
    					for(int l = 0; l < bucketElementCounts[k]; l++) {
    						//取出元素放入到arr
    						arr[index++] = bucket[k][l];
    					}
    				}
    				//第i+1轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
    				bucketElementCounts[k] = 0;
    			}
    		}
    	}
    }
    

    桶排序

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点:在额外空间充足的情况下,尽量增大桶的数量,使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中,数据范围在桶范围内。对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。

1、什么时候最快
当输入的数据可以均匀的分配到每一个桶中。

2、什么时候最慢
当输入的数据被分配到了同一个桶中。
/**
 * 描述:桶排序
 * 完成度:已完成
 * */
public class BarrelSort {

public static void main(String[] args) {
		
		int[] array = {1,1,1,1,1,1,1,1,0,1,2,3,5,4,9,7,8,6,10};
		
		int[] arr = new int[8000000];
		for (int i = 0; i < 8000000; i++) {
			arr[i] = (int) (Math.random() * 8000000); // 生成一个[0, 8000000) 数
		}
		
		long s1 = System.currentTimeMillis();
		new BarrelSort().barrelSort(arr);
		long s2 = System.currentTimeMillis();
		System.out.println("桶排序耗时:"+(s2-s1));


	}


	public int[] barrelSort(int[] array) {
		//1、找最大值
		int maxNum = Integer.MIN_VALUE;
		for(int i=0;i<array.length;i++) {
			if(array[i]>maxNum) {
				maxNum = array[i];
			}
		}
		
		//2、创建桶(范围是 max+1,应为数组从0开始)
		int[] bucketArray = new int[maxNum+1];
		
		//3、数据和桶编号做映射,如果映射关系成立,给桶标记
		for(int i=0;i<array.length;i++) {
			int num = array[i];
			//4、如果有桶映射有数据给桶编号+1标志,相同的数累加1
			bucketArray[num]=bucketArray[num]+1;
		}
		
		
		//5、遍历桶
        int n = 0;
		for (int i=0;i<bucketArray.length;i++) {
			//每个桶有bucketNum个数
			int bucketNum = bucketArray[i];
			//标记一个桶有多少个元素
			for(int k = 0 ;k<bucketNum;k++) {
				//array的第n个元素=第N个桶,桶内元素第n个
				array[n++] = i;
			}
		}
		return array;
	}
}

希尔排序

希尔排序法介绍希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。

希尔排序法基本思想是,希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4XS3JaJs-1685349042126)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\image-20230522161756819.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cGaFceDn-1685349042127)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\image-20230522161902505.png)]

public class ShellSort {

	public static void main(String[] args) {
		//int[] arr = { 8, 9, 1, 7, 2, 3, 5, 4, 6, 0 };
		
		// 创建要给80000个的随机的数组
		int[] arr = new int[5];
		for (int i = 0; i < 5; i++) {
			arr[i] = (int) (Math.random() * 8000000); // 生成一个[0, 8000000) 数
		}

		System.out.println("排序前");
		Date data1 = new Date();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String date1Str = simpleDateFormat.format(data1);
		System.out.println("排序前的时间是=" + date1Str);
		
		shellSort(arr); //交换式
		//shellSort2(arr);//移位方式
		
		Date data2 = new Date();
		String date2Str = simpleDateFormat.format(data2);
		System.out.println("排序前的时间是=" + date2Str);
		
		System.out.println(Arrays.toString(arr));
	}

	// 使用逐步推导的方式来编写希尔排序
	// 希尔排序时, 对有序序列在插入时采用交换法, 
	// 思路(算法) ===> 代码
	public static void shellSort(int[] arr) {
		
		int temp = 0;
		int count = 0;
		// 根据前面的逐步分析,使用循环处理
		for (int gap = arr.length / 2; gap > 0; gap = gap/2) {
			for (int i = gap; i < arr.length; i++) {
				// 遍历各组中所有的元素(共gap组,每组有个元素), 步长gap
				for (int j = i - gap; j >= 0; j = j-gap) {
					// 如果当前元素大于加上步长后的那个元素,说明交换
					if (arr[j] > arr[j + gap]) {
						temp = arr[j];
						arr[j] = arr[j + gap];
						arr[j + gap] = temp;
					}
				}
			}
		}
	}
	
	//对交换式的希尔排序进行优化->移位法
	public static void shellSort2(int[] arr) {
		
		// 增量gap, 并逐步的缩小增量
		for (int gap = arr.length / 2; gap > 0; gap /= 2) {
			// 从第gap个元素,逐个对其所在的组进行直接插入排序
			for (int i = gap; i < arr.length; i++) {
				int j = i;
				int temp = arr[j];
				if (arr[j] < arr[j - gap]) {
					while (j - gap >= 0 && temp < arr[j - gap]) {
						//移动
						arr[j] = arr[j-gap];
						j -= gap;
					}
					//当退出while后,就给temp找到插入的位置
					arr[j] = temp;
				}

			}
		}
	}

}

归并排序

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。 归并排序分为2步,拆分和合并。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RC0BYvB4-1685349042128)(C:\Users\hp\Documents\WeChat Files\god8816\FileStorage\Temp\1684744088632.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MXBE8UYi-1685349042128)(C:\Users\hp\Documents\WeChat Files\god8816\FileStorage\Temp\1684744136967.png)]

/**
 * 归并排序
 * 完成度:已完成
 * */
public class MergetSort {

	public static void main(String[] args) {
		//int arr[] = { 8, 4, 5, 7, 1, 3, 6, 2 }; //
		
		//测试快排的执行速度
		// 创建要给80000个的随机的数组
		int[] arr = new int[8000000];
		for (int i = 0; i < 8000000; i++) {
			arr[i] = (int) (Math.random() * 8000000); // 生成一个[0, 8000000) 数
		}
		System.out.println("排序前");
		Date data1 = new Date();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String date1Str = simpleDateFormat.format(data1);
		System.out.println("排序前的时间是=" + date1Str);
		
		int temp[] = new int[arr.length]; //归并排序需要一个额外空间
 		mergeSort(arr, 0, arr.length - 1, temp);
 		
 		Date data2 = new Date();
		String date2Str = simpleDateFormat.format(data2);
		System.out.println("排序前的时间是=" + date2Str);
 		
	}
	
	
	//分+合方法
	public static void mergeSort(int[] arr, int left, int right, int[] temp) {
		if(left < right) {
			int mid = (left + right) / 2; //中间索引
			//向左递归进行分解
			mergeSort(arr, left, mid, temp);
			//向右递归进行分解
			mergeSort(arr, mid + 1, right, temp);
			//合并
			merge(arr, left, mid, right, temp);
		}
	}
	
	//合并的方法
	/**
	 * 
	 * @param arr 排序的原始数组
	 * @param left 左边有序序列的初始索引
	 * @param mid 中间索引
	 * @param right 右边索引
	 * @param temp 做中转的数组
	 */
	public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
		
		int i = left; // 初始化i, 左边有序序列的初始索引
		int j = mid + 1; //初始化j, 右边有序序列的初始索引
		int t = 0; // 指向temp数组的当前索引
		
		//(一)
		//先把左右两边(有序)的数据按照规则填充到temp数组
		//直到左右两边的有序序列,有一边处理完毕为止
		while (i <= mid && j <= right) {
			//如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
			//即将左边的当前元素,填充到 temp数组 
			//然后 t++, i++
			if(arr[i] <= arr[j]) {
				temp[t] = arr[i];
				t += 1;
				i += 1;
			} else { //反之,将右边有序序列的当前元素,填充到temp数组
				temp[t] = arr[j];
				t += 1;
				j += 1;
			}
		}
		
		//(二)
		//把有剩余数据的一边的数据依次全部填充到temp
		while( i <= mid) { //左边的有序序列还有剩余的元素,就全部填充到temp
			temp[t] = arr[i];
			t += 1;
			i += 1;	
		}
		
		while( j <= right) { //右边的有序序列还有剩余的元素,就全部填充到temp
			temp[t] = arr[j];
			t += 1;
			j += 1;	
		}
		
		
		//(三)
		//将temp数组的元素拷贝到arr
		//注意,并不是每次都拷贝所有
		t = 0;
		int tempLeft = left; // 
		//第一次合并 tempLeft = 0 , right = 1 //  tempLeft = 2  right = 3 // tL=0 ri=3
		//最后一次 tempLeft = 0  right = 7
		while(tempLeft <= right) { 
			arr[tempLeft] = temp[t];
			t += 1;
			tempLeft += 1;
		}
		
	}
}

堆排序

堆排序基本介绍堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆, 注意 : 没有要求结点的左孩子的值和右孩子的值的大小关系。每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆大顶堆举例说明。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-95ErdP3Q-1685349042129)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\image-20230522164203118.png)]

2、经典算法介绍

递归算法

无处不在,就是自己循环调用自己。

回溯算法

【代码随想录】回溯能够解决的所有问题都能够抽象为树形结构(多叉树)。注意,回溯法解决的是在集合中递归地查找子集,集合大小就是树的宽度,递归的深度就是树的深度。着重注意:在集合中递归查找。 回溯算法剪枝是比较难的一部分。 常见leetcode题:组合问题、切割问题、子集问题、排列问题、棋盘问题、电话号码的字母组合

void backtracking(参数) {//1:函数参数及返回值
    if (终止条件) {	//2:终止条件
        存放结果;
        return;
    }
	//3:回溯搜索逻辑
    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

贪心算法

贪婪算法(贪心算法)是指在对问题进行求解时,在每一步选择中都采取最好或者最优(即最有利)的选择,从而希望能够导致结果是最好或者最优的算法。

贪婪算法所得到的结果不一定是最优的结果(有时候会是最优解),但是都是相对近似(接近)最优解的结果。

深度优先遍历

从一个点出发,选择一个遍历方向一直遍历到结束。

广度优先遍历

从一个点出发,尝试遍历更多平行节点。直到平行节点遍历完毕。

动态规划算法

利用递归暴利解决一类问题。 动态规划大致分5步: dp数组及下际的含义,递推公式、dp数组如何初始化、遍历顺序、打印dp数组。 常见leetcode题:背包问题、打家劫舍问题、股票问题、子序列问题。 个人感觉是算法中最难的,地推公式这关都不好过。

3、常见算法

1、迪杰斯特拉(Dijkstra)算法介绍

二、数据结构介绍

常用的数据结构,字符串,数组,链表,跳跃表,hash,平衡树、红黑树、B树、tire树、LSM树、treap树,有向图、无向图。 数据结构可视化网站推荐

数据结构平均时间最差时间稳定度
字符串---
数组---
链表---
HashO(1)O(1)稳定
跳跃表O(nlogn)O(n)不稳定
二叉树
大顶堆
小顶堆
红黑树稳定
B树
B+树
Treap树
LSM树
Trie树不稳定
无向图
有向图
带权图(也叫网)

1、字符串

字符串是最常用的数据结构,不同遍历算法不同,时间复杂度也不同。

2、数组

数组也是常用的数据结构,分为一维数组、多维数组、稀疏数组;稀疏数组常用于数据压缩数组;比如游戏地图

3、链表

链表分为单链表、双链表;不同遍历算法不同; 场景:LinkedList

4、Hash

Hash是一个时间复杂度最高的数据结构,但是其不能查询相邻数据信息。 场景:hashMap、redis

5、跳跃表

跳跃表结构多表;性能最好时接近hash,平均性能接近平衡树;最差性能接近字符串,是一种不稳定的数据结构; 场景:需要查询相邻数据的结构 redis Zset结构、ConcurrentSkipListMap、ConcurrentSkipListSet

6、二叉树

二叉树有很多种类;满二叉树、完全二叉树、顺序存储二叉树、线索化二叉树、平衡二叉树(AVL);我们用最多的是平衡二叉树、顺序存储二叉树、替罪羊树、赫夫曼树。

满二叉树定义:如果该二叉树的所有叶子节点都在最后一层,并且结点总数= 2^n -1 , n 为层数,则我们称为满二叉树。

完全二叉树定义:如果该二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续,我们称为完全二叉树。

平衡二叉树: 平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树, 可以保证查询效率较高。具有以下特点:它是一. 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等

其他的;请看韩顺平老师讲解,我们最常用的二叉树就是平衡二叉树、红黑树

7、大顶堆

二叉树的一种;每个结点的值都大于或等于其左右孩子结点的值。 场景:少见

8、小顶堆

二叉树的一种;每个结点的值都小于或等于其左右孩子结点的值。 场景:少见

9、红黑树

平衡二叉树的一种;使用频率最高的二叉树; 场景:hashmap;操作系统;nginx

10、B树

B树是IO友好型树;其使用场景是:mysql innodb存储引擎下非聚集索引,MyiSam索引引擎,这2者区别前者记录的是主键id,需要从主键查询数据。 后者记录的是数据的硬件地址,直接从目标寻址,时间复杂度O(1).

11、B+树

B+树是IO友好型树;其使用场景是:mysql innodb存储引擎下聚集索引,其特点子节点记录了大量的数据,子节点通过双向链表串联起来。

12、Treap树

二叉随机平衡收索堆树;使用场景不详细

13、LSM树

14、Trie树

15、多叉树

16、无向图

17、有向图

18、带权图(网)

左边连续,倒数第二层的叶子节点在右边连续,我们称为完全二叉树。

平衡二叉树: 平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树, 可以保证查询效率较高。具有以下特点:它是一. 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等

其他的;请看韩顺平老师讲解,我们最常用的二叉树就是平衡二叉树、红黑树

7、大顶堆

二叉树的一种;每个结点的值都大于或等于其左右孩子结点的值。 场景:少见

8、小顶堆

二叉树的一种;每个结点的值都小于或等于其左右孩子结点的值。 场景:少见

9、红黑树

平衡二叉树的一种;使用频率最高的二叉树; 场景:hashmap;操作系统;nginx

10、B树

B树是IO友好型树;其使用场景是:mysql innodb存储引擎下非聚集索引,MyiSam索引引擎,这2者区别前者记录的是主键id,需要从主键查询数据。 后者记录的是数据的硬件地址,直接从目标寻址,时间复杂度O(1).

11、B+树

B+树是IO友好型树;其使用场景是:mysql innodb存储引擎下聚集索引,其特点子节点记录了大量的数据,子节点通过双向链表串联起来。

12、Treap树

二叉随机平衡收索堆树;使用场景不详细

13、LSM树

14、Trie树

15、多叉树

16、无向图

17、有向图

18、带权图(网)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/585235.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++中的函数组合:用std::function实现编程艺术

C中的函数组合&#xff1a;用std::function实现编程艺术 1. 引言1.1 C中的函数式编程 (Functional Programming in C)1.2 函数组合的概念和价值 (Concept and Value of Function Composition)1.3 std::function概述 (Overview of std::function) 2. 如何在C中实现函数组合 (Imp…

【网络协议详解】——万维网WWW系统协议(学习笔记)

目录 &#x1f552; 1. 概述&#x1f552; 2. 文本传输协议HTTP&#x1f552; 3. HTTP的报文格式&#x1f552; 4. Cookie&#x1f552; 5. 万维网缓冲与代理服务器 &#x1f552; 1. 概述 万维网www&#xff08;World Wide Web&#xff09;并非某种特殊的计算机网络。它是一个…

两个iframe同时滚动实现界面内容对比功能

背景&#xff1a;因为要实现一个版本对比功能&#xff0c;所以要保证两个界面能同时滚动。&#xff08;本文只讲同时滚动&#xff0c;对比功能文本只讲思路&#xff0c;具体代码实现如有需要 可以联系我&#xff09;&#xff0c;因为过程中有部分收获特此记录。 本文参考&…

Jetson硬件 升级jetpack系统 版本流程

前言&#xff1a; 准备一个linux系统电脑&#xff0c;一个跳线帽&#xff0c;以及一条usb线 以及英伟达开发者账号&#xff0c;点击https://developer.nvidia.com/zh-cn/embedded/jetpack进行注册 注意&#xff1a;烧录的目标硬件是以前装过低版本的jetpack&#xff0c;以下步…

工业自动化新引擎:工业机器人引领制造业转型升级

自2010年开始&#xff0c;我国15-64岁人口比例下滑&#xff0c;截至2022年我国总人数出现负增长&#xff0c;同比下滑0.1%&#xff0c;因人口老龄化加剧和出生率的持续走低&#xff0c;致使进入生产体系的劳动力越来越少。 随着我国经济进入新常态&#xff0c;制造业面临着产能…

通过训练NLP制作一个自己的简易输入法

最近开始研究NLP&#xff0c;然后根据手写CV UP主的视频&#xff0c;写了一个N Gram的NLP模型&#xff0c;算是该领域里的hello world吧。然后我又添加了几行代码实现了一个非常简易的输入法。 项目说明&#xff1a; 数据集可以自创&#xff0c;导入txt文件即可&#xff1b; …

K8s in Action 阅读笔记——【6】Volumes: attaching disk storage to containers

K8s in Action 阅读笔记——【6】Volumes: attaching disk storage to containers 在前三章中&#xff0c;我们介绍了Pods以及它们与ReplicationControllers、ReplicaSets、DaemonSets、Jobs和Services等Kubernetes资源的交互。现在&#xff0c;我们将回到Pod内部&#xff0c;…

【java 基础一】 纯语法基础记录

一、基础 1.1 变量 Java 变量是程序中存储数据的容器。 在 Java 中&#xff0c;变量需要先声明再使用&#xff0c;并且必须先声明再赋值。 声明变量&#xff1a;声明变量时需要指定变量的类型、名称和初始值。例如&#xff0c;声明一个整型变量可以如下所示&#xff1a; in…

水处理施工方案合集

编制说明及工程简介 (一) 编制说明 本施工组织设计是依据建设单位提供的招标文件、施工图、同类工程施工资料和国家有关施工规范及验收标准进行编制的。本施工组织设计针对本工程施工中的关键点、难点及其处理措施&#xff0c;主要施工方法&#xff0c;施工组织部署&#xff…

如何理解 CRM 客户关系管理系统?

如何理解 CRM 客户关系管理系统&#xff1f; CRM的作用不止是工具&#xff0c;根据用户和对象的不同&#xff0c;CRM创造的价值也是不同的。 打个比方: 有的企业是用CRM来管理客户信息;有的企业是用CRM来获取流量的&#xff1b;有的企业是用CRM来做销售管理的&#xff1b;还…

Springboot整合OSS并实现文件上传和下载

目录 一.OSS服务器开通并创建账户 二.Springboot整合OSS 1.创建springboot项目 2.整合OSS 三.postman测试 一.OSS服务器开通并创建账户 参考阿里云OSS的使用(全程请登陆)_zhz小白的博客-CSDN博客https://blog.csdn.net/zhouhengzhe/article/details/112077301 二.Springb…

深度学习笔记之循环神经网络(八)LSTM的轻量级变体——门控循环单元(GRU)

深度学习笔记之LSTM轻量级变体——门控循环单元[GRU] 引言回顾&#xff1a; LSTM \text{LSTM} LSTM的前馈计算过程 LSTM \text{LSTM} LSTM的问题 GRU \text{GRU} GRU的前馈计算过程 GRU \text{GRU} GRU的优势 引言 上一节介绍了从反向传播过程的角度认识 LSTM \text{LSTM} LST…

【29】核心易中期刊推荐——计算语言学人工智能(AI)技术

🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…

使用javascript-obfuscator给js文件加密

一、安装javascript-obfuscator包 npm install javascript-obfuscator -g二、默认配置直接压缩文件 javascript-obfuscator miniprogram/src/utils/utils_create_sign.js --output miniprogram/src/utils/create_sign.js三、根据配置文件压缩文件 3.1、创建mixs.json配置文…

前端阿里云OSS直传,微信小程序版本

前言&#xff1a; 网络上许多的文章资料&#xff0c;全是使用阿里云官方的SDK&#xff0c;ali-oss插件去做直传。可是各位素未谋面的朋友要注意&#xff0c;这个SDK它支持web环境使用&#xff0c;也就是PC端浏览器。 当项目环境切换到微信小程序&#xff0c;是无法使用这种方…

Power BI Embedded自动缩放容量,为公司每个月节省上万元

哎&#xff0c;不知道今年行情怎么就这样了&#xff0c;大厂一边大批毕业生&#xff0c;一边大量招人。难道是今年的新人便宜&#xff1f;就连道哥&#xff08;吴翰清&#xff0c;阿里P10&#xff0c;中国顶级黑客&#xff09;都从阿里离职了&#xff0c;当年年少不懂学计算机&…

Nodejs批量处理图片小工具:批量修改图片信息

小工具一&#xff1a;批量修改文件夹里面的图片名称 步骤&#xff1a; 1.安装nodejs。 2.根据需要修改editFileName(filePath, formatName)函数的参数&#xff0c;也可以不改&#xff0c;直接将renameFile.js和img文件夹放在同一个目录下。 3.在renameFile.js目录下开启终端…

SQL报错this is incompatible with sql_mode=only_full_group_by

一、bug记录 1.1.bug截图 1.2.sql语句 SELECT id,batch_no,if_code,channel_mch_no,bill_date,bill_type,currency,order_id, channel_order_no,channel_amount,channel_fee_amount,channel_success_at, channel_user,channel_state,org_pay_order_id,channel_refund_amoun…

曾经由盛转衰的骈文,却引领后人在文质兼美的创作之路上坚定前行

又叫骈体文&#xff0c;是和散文相对应的一种文体&#xff0c;它兴起于汉末&#xff0c;形成于魏晋&#xff0c;最盛行于南北朝&#xff0c;在初唐、中唐、唐末、五代、宋初时也盛极一时。古人语&#xff1a;两马并驾为骈&#xff0c;所以骈文最大的特点是用对偶的手法&#xf…

Fiddler抓包工具之fiddler设置手机端抓包

fiddler设置手机端抓包 安卓手机抓包 第一步&#xff1a;配置电脑和安卓的相关设置 1、手机和fiddler位于同一个局域网内&#xff1b;首先从fiddler处获取到ip地址和端口号&#xff1a; &#xff0c;点击online&#xff0c;最后一行就是ip地址 2、路径&#xff1a;Tools》O…