查找、排序、二叉树的算法,统统记录于此。

news2024/9/28 9:33:11

文章目录

  • 一、查找
    • 1. 无序表的顺序查找
    • 2. 折半查找
    • 3. 分块查找
    • 4. 二叉排序树BST
    • 5. 哈希表查找
  • 二、排序
    • 1. 不带哨兵的直接插入排序
    • 2. 带哨兵的直接插入排序
    • 3. 带哨兵、折半查找的直接插入排序
    • 4. 希尔排序
    • 5. 冒泡排序
    • 6. 快速排序
    • 7. 选择排序
    • 8. 堆排序
    • 9. 归并排序
  • 二叉树
    • 1. 递归先序遍历
    • 2. 非递归先序遍历
    • 3. 递归中序遍历
    • 4. 非递归中序遍历
    • 5. 递归后序遍历
    • 6. 非递归后序遍历
    • 7. 广度遍历二叉树
    • 8. 深度遍历

一、查找

1. 无序表的顺序查找

把待查关键字key存入表头(哨兵),从后向前逐个比较,可免去查找过程中每一步都要检测是否查找完毕,加快速度。

// 下标从1开始,头节点为空
public static int sentrySearch(int[] arr, int target){
	arr[0] = target;
	int index = arr.length-1;
	while(arr[index] != target){
		--index;
	}
	if(index == 0) return -1;
	return index;
}
  • 空间复杂度:O(1)
  • 时间复杂度:O(n)
  • 平均查找长度:ASL =(n+1)/ 2

2. 折半查找

首先将给定值key与表中中间位置的元素比较,若相等则查找成功,返回该元素的存储位置;若不等则所需查找的元素只能在中间元素以外的前半部分或后半部分。

public static int Sort(int[] nums, int target){
	int low = 0;
	int high = nums.length;
	while(low < high){
		mid = (low + high) / 2;
		if(target == nums[mid]) return mid;
		if(target < nums[mid]) high = mid-1;
		if(target > nums[mid]) low = mid+1;
	}
	return -1
}
  • 空间复杂度:O(1)
  • 时间复杂度:O( l o g 2 log_2 log2n)
  • 平均查找长度:ASL = l o g 2 log_2 log2(n+1)

3. 分块查找

分块查找又称索引顺序查找,它是顺序查找的一种改进方法:将n个数据元素“按块有序”划分为m块(m<=n)。每一块中的数据元素不必有序,但块与块之间必须“按块有序”,即第1快中的任一元素的关键字都必须小于第2块中任一元素的关键字;而第2块中任一元素又都小于第3块中的任一元素,……

查找分两部分:先对索引表进行二分查找或顺序查找,以确定待查记录在哪一块中;然后在已确定的快中用顺序法进行查找。

@AllArgsConstructor
class IndexItem {
	public int index; //值比较的索引
 	public int start; //开始位置
	public int length;//块元素长度(非空)
}

public int indexSearch(int key){
	int[] mainList = new int[]{
		22, 12, 13, 8, 9, 20, 
		33, 42, 44, 38, 24, 48,
		60, 58, 74, 49, 86, 53
	}

	IndexItem[] indexItemList = new IndexItem[]{
		new IndexItem(22,1,6),
		new IndexItem(48,7,6),
		new IndexItem(86,13,6);
	}

	// 第一步,查找在哪一块
	int index = 0;
	for(;index < indexItemList.length; index++){
		if(indexItemList[index].index >= key ) break;
	} 

	int num = 0;
	for(int i=0; i<index; i++){
		num += indexlist[i].length;
	}

	for(int i=num; i<num+indexItemList.length; i++){
		if(MainList[i] == key) return i;
	}

	return -1;
}
  • 时间复杂度:O(log(m)+n/m),n个数据分成m块
  • 平均查找长度:ASL=ASL折半查找+ASL顺序查找= l o g 2 log_2 log2(m+1) +(n/m+1)/2

4. 二叉排序树BST

    private static class BinaryTreeNode {
        int data;
        BinaryTree lchild;
        BinaryTree rchild;
    }

public class BinarySearchTree {

    public static BinaryTreeNode serachBinaryTree(BinaryTreeNode btn, int key) {
        if (btn == null) { // 树节点不存在,返回
            return new BinaryTreeNode();
        } else if (key == btn.data) { // 查找成功
            return btn;
        } else if (key < btn.data) { // 关键字小于根节点查找左子树
            return serachBinaryTree(btn.lchild, key);
        } else { // 关键字大于根节点查找右子树
            return serachBinaryTree(btn.rchild, key);
        }
    }
}
  • 时间复杂度:O(logn)
  • 空间复杂度:O(1)
  • 平均查找长度ASL:查找成功的平均查找长度、查找失败的平均查找长度
    在这里插入图片描述
    在这里插入图片描述

5. 哈希表查找

常用的哈希函数

  • 直接地址法:H(key)=key或H(key)=a*key+b
  • 除留余数法:H(key)= key mod p
  • 数字分析法:可选取关键字的若干数位组成哈希地址,原则是使得到的哈希地址尽量避免冲突。
  • 平方取中法:取关键字平方后的中间几位为哈希地址
    常用的处理冲突方法
  • 开发地址法:有线性探查法和平方探查法
  • 链式地址法:把所有的同义词用单链表链接起来的方法,种方哈希表中每个单元中存放的不再是记录本身,而是相应同义词单链表的头指针。
  • 时间复杂度:O(1)
  • 空间复杂度:O(n)

二、排序

注意:下标都是从1开始的

1. 不带哨兵的直接插入排序

public void InsertSort(int nums[]){
	int temp;
	for(int i=2; i<nums.length; i++){
		temp = nums[i];
		int j = i;
		while(nums[j]<nums[j-1] && j > 1){
			nums[j] = nums[j-1];
		}
		nums[j+1] = temp;
	}
}
  • 时间复杂度:最差时间复杂度O(n2)、平均时间复杂度O(n2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

2. 带哨兵的直接插入排序

public void InsertSort(int nums[]){
	for(int i=2; i<nums.length; i++){
		nums[0] = nums[i];
		int j = i;
		while(nums[j]<nums[j-1]){
			nums[j] = nums[j-1];
		}
		nums[j+1] = nums[0];
	}
}
  • 时间复杂度:最差时间复杂度O(n2)、平均时间复杂度O(n2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

3. 带哨兵、折半查找的直接插入排序

折半查找跟顺序查找的效率都是一样的,因为将元素向后退的次数是一样的。

public void InsertSort(int nums[]){
	int low,high,mid;
	for(int i=2;i<=n;i++){
		A[0]=A[i];
		low=1;high=i-1;
		while(low<=high){
			mid=(low+high)/2;
			if(A[mid]>A[0]) high=mid-1;			//可用A[0],也可用A[i]
			else low=mid+1
		}
		for(int j=i-1;j>=high+1;--j)	//注意这里只能用high,不能用low,mid
			A[j+1]=A[j];
		A[high+1]=A[0];
	}
}
  • 时间复杂度:最差时间复杂度O(n2)、平均时间复杂度O(n2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

4. 希尔排序

先追求表中元素的部分有序,再逐渐逼近全局有序。

public void ShellSort(int arr[], int gap){
	while(gap>=1){
		for(int i=0; i<gap; i++){
			for(int j=i+gapl j<arr.length; j+=gap){
				int temp = arr[i];
				for(int k = j-gap; k>=i&&arr[k]>temp; k-=gap){
						arr[k+gap] = arr[k];
				}
				arr[k+gap] = temp;
			}
		}
	}
}
  • 时间复杂度:O(n1.3~2)
  • 空间复杂度:O(1)
  • 稳定性:不稳定

5. 冒泡排序

public static void BubbleSort(int nums[]){
	for(int i = 1; i< nums.length; i++){
		boolean flag = true;
		for(int j = 0; j<nums.length-i; j++){
			if(arr[j] > arr[j+1]){
				int temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;

				flag = false;
			}
		}
		if(flag) break;
	}
}
  • 时间复杂度:最坏时间复杂度O(n2)、平均时间复杂度O(n2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

6. 快速排序

public void quickSort(int[] nums, int left, int right){
	
	while(left >= right) return;
	
	int pivot = a[left];
	int i=left;
	int j=right;

	while(i < j){
		while(pivot <= a[j] && i<j) j--;
		while(pivot >= a[i] && i<j) i++;

		int temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

	a[left] = a[i];
	a[i] = pivot;
   	
   	quickSort(a,left,i-1);//对左边的子数组进行快速排序
   	quickSort(a,i+1,right);//对右边的子数组进行快速排序
}
  • 时间复杂度:最差时间复杂度O(n2)、平均时间复杂度O(n2)
  • 空间复杂度:O(log2n)~O(n)
  • 稳定性:不稳定

7. 选择排序

public void SelectSort(int[] nums){
	for(int i=0; i<nums.length; i++){
		int temp = i;
		for(int j=i+1; j<nums.length; j++){
			if(nums[j] < nums[temp]) temp = j;
		}
		int swap = nums[i];
		nums[i] = nums[temp];
		nums[temp] = swap;
	}
}
  • 时间复杂度:最差时间复杂度O(n2)、平均时间复杂度O(n2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

8. 堆排序

堆排序分为两个过程:输出堆顶、调整新堆

void HeadAdjust(int A[],int k,int len){		//调整指定根节点A[k]
	A[0]=A[k];
	for(int i=k*2;i<=len;i*=2){
		if(i<len&&A[i]<A[i+1]) i++;		//不管要不要交换,先选出最大的子结点
		if(A[0]>=A[i]) break;		//不用交换,而且后面是一定调整好的了
		else{
			A[k]=A[i]
			k=i;			//这里与A[K]=A[0]相呼应,其实也可以选择A[i]=A[0],每次都交换
		}
	}
	A[k]=A[0];
}

void BuildMaxHeap(int A[],int len){	//从最后一个子树根节点开始调整,调整全部根节点
	for(int i=len/2;i>0;--i)			
		HeadAdjust(A,i,len);
}

void HeapSort(int A[],int len){
	BuildMaxHeap(A,len);			//堆初始化
	
	for(i=len;i>1;i--){				
		Swap(A[i],A[1]);			//将最大值放在最后,然后重新在指定位置调整
		HeapAdjuest(A,1,i-1)		//截断最后一位,并且重新从第一位调整
	}
}
  • 时间复杂度:最差时间复杂度O(nlog2n)、平均时间复杂度O(nlog2n)
  • 空间复杂度:O(1)
  • 稳定性:不稳定

9. 归并排序

把两个或多个已经有序的序列合并成一个

public static int[] sort(int[] a,int low,int high){
        int mid = (low+high)/2;
        if(low<high){
            sort(a,low,mid);
            sort(a,mid+1,high);
            //左右归并
            merge(a,low,mid,high);
        }
        return a;
    }
     
    public static void merge(int[] a, int low, int mid, int high) {
        int[] temp = new int[high-low+1];
        int i= low;
        int j = mid+1;
        int k=0;
        // 把较小的数先移到新数组中
        while(i<=mid && j<=high){
            if(a[i]<a[j]){
                temp[k++] = a[i++];
            }else{
                temp[k++] = a[j++];
            }
        }
        // 把左边剩余的数移入数组 
        while(i<=mid){
            temp[k++] = a[i++];
        }
        // 把右边边剩余的数移入数组
        while(j<=high){
            temp[k++] = a[j++];
        }
        // 把新数组中的数覆盖nums数组
        for(int x=0;x<temp.length;x++){
            a[x+low] = temp[x];
        }
    }
  • 时间复杂度:最差时间复杂度O(nlog2n)、平均时间复杂度O(nlog2n)
  • 空间复杂度:O(n)
  • 稳定性:稳定

二叉树

1. 递归先序遍历

public static void preOrder(TreeNode root){
	if(root == null) return;
	
	System.out.println(root.value);
	if(root.left != null) PreOrder(root.left);
	if(root.right != null) PreOrder(root.right);
}

2. 非递归先序遍历

public static void preOrder(TreeNode root){
	Stack<TreeNode> stack = new Stack<TreeNode>();
	while(root != null || !stack.isEmpty()){
		while(root!=null){							// 1. 下去的时候
			System.out.println(root.value);		// 访问
			stack.push(root);					// 入栈
			root = root.left					// 左孩子
		}
		if(!stack.isEmpty()){		// 2. 回来的时候
			root = stack.pop();					// 出栈
			root = root.right;					// 右孩子
		}
	}
}

3. 递归中序遍历

public static void midOrder(TreeNode root){
	if(root == null) return;
	
	if(root.left != null) PreOrder(root.left);
	System.out.println(root.value);
	if(root.right != null) PreOrder(root.right);
}

4. 非递归中序遍历

public static void minOrder(TreeNode root){
	Stack<TreeNode> stack = new Stack<TreeNode>();
	while(root != null || !stack.isEmpty()){
		while(root!=null){							// 1. 下去的时候
			stack.push(root);					// 入栈
			root = root.left					// 左孩子
		}
		if(!stack.isEmpty()){		// 2. 回来的时候
			root = stack.pop();					// 出栈
			System.out.println(root.value);		// 访问
			root = root.right;					// 右孩子
		}
	}
}

5. 递归后序遍历

public static void postOrder(TreeNode root){
	if(root == null) return;
	
	if(root.left != null) PreOrder(root.left);
	if(root.right != null) PreOrder(root.right);
	System.out.println(root.value);
}

6. 非递归后序遍历

public void postorderTraversal(TreeNode root) {
    Deque<TreeNode> stack = new LinkedList<TreeNode>();
	TreeNode prev = null;			// prev是指上一个遍历到的结点
    
    if (root == null) return res;

    while (root != null || !stack.isEmpty()) {
        while (root != null) {
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();

		// 要是没有右孩子,或者右孩子已经看过了,就打印根结点
        if (root.right == null || root.right == prev) {
            System.out.println(root.value);
            prev = root;		// 保留最近遍历过的一次结点
            root = null;		//这里设为null,就是好好的把结点输出
        } 
        // 右孩子不是空的,并且上次prev没有走过的,就push进栈。
        else{	 
			stack.push(root);
            root = root.right;
		}
    }
}

7. 广度遍历二叉树

public  static void bfs(TreeNode root){
	Queue<TreeNode> queue = new LinkedList<TreeNode>();

	if(root == null) return;
	queue.add(root);
	
	while(!queue.isEmpty()){
		TreeNode t = queue.remove();
		System.out.println(root.value);	
		if(t.left != null) queue.add(t.left);
		if(t.right != null) queue.add(t.right);
	}
}

8. 深度遍历

    public void dfs(TreeNode root){
        Stack<TreeNode> stack=new Stack<TreeNode>();
 
        if(root==null)
            return list;
	    
	    //压入根节点
        stack.push(root);
    	
    	//然后就循环取出和压入节点,直到栈为空,结束循环
        while (!stack.isEmpty()){
            TreeNode t=stack.pop();
            if(t.right!=null)
                stack.push(t.right);
            if(t.left!=null)
                stack.push(t.left);
            System.out.println(t.value);
        }
}

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

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

相关文章

八,iperf3源代码分析:状态机及状态转换过程--->运行正向TCP单向测试时的客户端代码

本文目录一、测试用命令二、iperf3客户端状态机中各个状态解析状态机迁移图运行正向TCP单向测试时的客户端的状态列表三、iperf3客户端状态机迁移分析A-初始化测试对象&#xff08;NA--->初始化状态&#xff09;:B-建立控制连接&#xff0c;等待服务端PARAM_EXCHANGE的指令&…

西电机试数据结构核心算法与习题代码汇总(机考真题+核心算法)

文章目录前言一、链表问题1.1 反转链表1.1.1 题目1.1.2 代码1.2 多项式加减法1.2.1 题目1.2.2 代码二、队列和栈2.1 学生退学2.1.1 问题2.1.2 代码三、矩阵和串题目3.1 矩阵对角线求和3.1.1 问题3.1.2 代码四、排序问题4.1 多元素排序4.1.1 问题4.1.2 代码五、二叉树5.1 相同二…

synchronize优化偏向锁

偏向锁 轻量级锁在没有竞争时&#xff08;只有自己一个线程&#xff09;&#xff0c;仍然会尝试CAS替换mark word&#xff1b; 会造成一定的性能的损耗&#xff1b; JDK6之中引入了偏向锁进行优化&#xff0c;第一次使用时线程ID注入到Mark word中&#xff0c;之后重入不再进…

旅游预约APP开发具有什么优势和功能

旅游活动目前正在作为广大用户休闲娱乐的一个首选内容&#xff0c;不仅是公司团建活动可以选择旅游&#xff0c;而且一些节假日也可以集结自己的亲朋好友来一次快乐有趣的旅游活动&#xff0c;随着当代人对于旅游的需求呈现上升的趋势&#xff0c;也让旅游预约APP开发开始流行并…

大家都在用哪些研发流程管理软件?

全球知名的10款流程管理软件分享&#xff1a;1.IT/研发项目流程管理&#xff1a;PingCode&#xff1b;2.通用项目流程管理&#xff1a;Worktile&#xff1b;3.销售流程管理&#xff1a;Salesforce Workflow&#xff1b;4.合同流程管理&#xff1a;Agiloft&#xff1b;5.IBM Bus…

20230308 APDL Lsdyna结构学习笔记

可以用鼠标右键进行结构的旋转视图。 一、编辑材料 输入参数分别为: 密度; 弹性模量; 泊松比; 屈服应力; 切线模量 由于模型是分块建立的,这里需要把模型进行粘接 点击booleans(布尔工具) 点击Glue、areas,结构物是由面单元构成的

ReactDOM.render函数内部做了啥

ReactDOM.render函数是整个 React 应用程序首次渲染的入口函数&#xff0c;它的参数是什么&#xff0c;返回值是什么&#xff0c;函数内部做了什么&#xff1f; ReactDOM.render(<App />, document.getElementById("root")); 前序 首先看下首次渲染时候&…

二叉树OJ题目详解

根据二叉树创建字符串 采用前序遍历的方式&#xff0c;将二叉树转换成一个由括号和数字组成的字符串。 再访问每一个节点时&#xff0c;需要分情况讨论。 如果这个节点的左子树不为空&#xff0c;那么字符串应加上括号和左子树的内容&#xff0c;然后判断右子树是否为空&#x…

VBA小模板,跨表统计的2种写法

目标 1 统计一个excel 文件里&#xff0c;多个sheet里的内容2 有的统计需求是&#xff0c;每个表只单表统计&#xff0c;只是进行批量操作3 有的需求是&#xff0c;多个表得某些行列累加等造出来得文件 2 实现方法1 &#xff08;可能只适合VBAEXCEL&#xff0c;不太干净的写法…

一文带你了解,前端模块化那些事儿

文章目录前端模块化省流&#xff1a;chatGPT 总结一、参考资料二、发展历史1.无模块化引出的问题:横向拓展2.IIFE3.Commonjs(cjs)4.AMD引出的问题&#xff1a;5.CMD6.UMD7.ESM往期精彩文章前端模块化 省流&#xff1a;chatGPT 总结 该文章主要讲述了前端模块化的发展历史和各个…

css伪类和伪元素的区别

文章目录什么是css伪类和伪元素css伪类和伪元素有什么用&#xff1f;css伪类的具体使用常见的伪类伪元素的具体使用常见的伪元素什么是css伪类和伪元素 伪类和为元素是两个完全不同且重要的概念&#xff0c;它们的作用是给元素添加一些特殊的效果或样式 伪类用于选择某个元素的…

Kalman Filter in SLAM (6) ——Error-state Kalman Filter (EsKF, 误差状态卡尔曼滤波)

文章目录0.前言1. IMU的误差状态空间方程2. 误差状态观测方程3. 误差状态卡尔曼滤波4. 误差状态卡尔曼滤波方程细节问题0.前言 这里先说一句&#xff1a;什么误差状态卡尔曼&#xff1f;完全就是在扯淡&#xff01; 回想上面我们推导的IMU的误差状态空间方程&#xff0c;其实…

乐山持点科技:抖客推广准入及准出管理规则

抖音小店平台新增《抖客推广准入及准出管理规则》&#xff0c;本次抖音规则具体如下&#xff1a;第一章 概述1.1 目的及依据为维护精选联盟平台经营秩序&#xff0c;保障精选联盟抖客、商家、消费者等各方的合法权益;根据《巨量百应平台服务协议》、《“精选联盟”服务协议(推广…

【GNN/深度学习】常用的图数据集(资源包)

【GNN/深度学习】常用的图数据集&#xff08;图结构&#xff09; 文章目录【GNN/深度学习】常用的图数据集&#xff08;图结构&#xff09;1. 介绍2. 图数据集2.1 Cora2.2 Citeseer2.3 Pubmed2.4 DBLP2.5 ACM2.6 AMAP & AMAC2.7 WIKI2.8 COCS2.9 BAT2.10 EAT2.11 UAT2.12 C…

第十三届蓝桥杯省赛Python大学B组复盘

目录 一、试题B&#xff1a;寻找整数 1、题目描述 2、我的想法 3、官方题解 4、另解 二、试题E&#xff1a;蜂巢 1、题目描述 2、我的想法 3、官方题解 三、试题F&#xff1a;消除游戏 1、题目描述 2、我的想法&#xff08;AC掉58.3%&#xff0c;剩下全超时&#x…

Substrate 基础教程(Tutorials) -- 监控节点指标

Substrate 公开有关网络操作的度量。例如&#xff0c;您可以收集有关您的节点连接了多少个对等节点、您的节点使用了多少内存以及正在生成的块数量的信息。为了捕获和可视化Substrate节点公开的度量&#xff0c;您可以配置和使用Prometheus和Grafana等工具。本教程演示如何使用…

C++学习笔记(以供复习查阅)

视频链接 代码讲义 提取密码: 62bb 文章目录1、C基础1.1 C初识&#xff08;1&#xff09; 第一个C程序&#xff08;2&#xff09;注释&#xff08;3&#xff09;变量&#xff08;4&#xff09;常量&#xff08;5&#xff09;关键字&#xff08;6&#xff09;标识符命名规则1.2 …

mysql 导入超大sql文件

mysql -u root -p 登录mysql命令 可以登陆mysql服务器使用source命令导入&#xff0c;会快很多&#xff0c;我这里导入500M&#xff0c;大概用了5分钟。 1. liunx登陆mysql mysql -u 用户名 -p 数据库名 然后输入密码 登陆mysql控制台后&#xff0c;执行source命令&#xf…

Maven - Linux 服务器 Maven 环境安装与测试

目录 一.引言 二.安装流程 1.获取安装包 2.解压并安装 3.配置环境 4.mvn 验证 三.测试踩坑 1.Permission denied 2.Plugin or dependencies Error 一.引言 通道机上的 java 项目需要 mvn package 提示没有 mvn 命令&#xff0c;下面记录下安装 maven 的全过程。 二.安…

BatchNorm1d的复现以及对参数num_features的理解

0. Intro 以pytorch为例&#xff0c;BatchNorm1d的参数num_features涉及了对什么数据进行处理&#xff0c;但是我总是记不住&#xff0c;写个blog帮助自己理解QAQ 1. 复现nn.BatchNorm1d(num_features1) 假设有一个input tensor&#xff1a; input torch.tensor([[[1.,2.,…