左神算法笔记05

前缀树

定义

输入字符串,按字符出现的顺序存到多叉树中。可以通过该树以O[str.lenth]的时间复杂度获取到添加了几次给定字符串str,或以str为前缀的字符串在该树中添加了几个,以及删除功能。

代码

public class Node
{
	private int pass;
	private int end;
	private Node[] nexts;

	public Node()
	{
		pass = 0;
		end = 0;
		nexts = new Node[26];//共26个字母所以只用26个数组
	}
}

public class Triel
{
	private Node root;
	public Triel()
	{
		root = new Node();
	}

	/*
	* 插入新字符串
	* 
	*/
	public Boolean insert(String str)
	{
		if (str == null)//空字符串直接返回false
			return false;
		char[] chs = str.toCharArray();//转化成char数组
		Node n = root;
		n.pass++;//根节点经过次数增加
		int index = 0;
		for(int i = 0;i < chs.lenth;i++)
		{
			index = chs[i] - 'a';//获取字母对应的下标
			if(n.nexts[index] == null)//原来的树上没有该节点
				n.nexts[index] = new Node();//新建节点
			n = n.nexts[index];//节点后移
			n.pass++;//节点经过次数增加
		}
		//结束循环时,代表字符串全部结束,此时来到最后一个字符对应的节点
		n.end++;//节点结束次数增加
		return true;
	}
	
	/**
	* 查询添加过几次str字符串
	* 过程基本同插入
	*/
	public int search(String str)
	{
		if(str == null) return 0;
		char[] chs = str.toCharArray();
		Node n = root;
		int index = 0;
		for(int i = 0;i < chs.lenth;i++)
		{
			index = chs[i] - 'a';
			//与插入的不同点,如果发现下一个节点不存在,就可以直接返回没添加过str字符串
			if(n.nexts[index] == null) return 0;
			n = n.nexts[index];
		}
		//返回以最后一个字符为结束的次数
		return n.end;
	}

	/**
	* 删除一次str字符串
	*
	*/
	public Boolean delete(String str)
	{
		if(search(str) != 0)//先判断树中是否添加过该字符串,没有返回false
		{
			Node n = root;
			n.pass--;//经过的节点减一
			char[] chs = str.toCharArray();
			int index = 0;
			for(int i = 0;i < chs.lenth;i++)
			{
				index = chs[i] - 'a';
				//如果有一个节点的经过次数减为0,则说明该节点及其后的节点在删除后都变成冗余部分
				//要删除该节点及其后的节点
				//所以通过其父节点对他的经过次数进行计算,要删除则直接将该指针置为null
				//注意:如果是C、C++,则要手动释放空间
				if(--n.nexts[index].pass == 0) 
				{
					n.nexts[index] = null;
					return true;
				}
				n = n.nexts[index];
			}
			n.end--;
			return true;
		}
		return false;
	}

	/**
	* 查询以str为前缀的字符串在树中添加了几次
	*
	*/
	public int searchPre(String str)
	{
		if(str == null) return 0;
		Node n = root;
		char[] chs = str.toCharArray();
		int index = 0;
		for(int i = 0;i < chs.lenth;i++)
		{
			index = chs[i] - 'a';
			if(n.nexts[index] == null) return 0;
			n = n.nexts[index];
		}
		return n.pass;
	}
}

拓展

如果字符的数量更多,可以用hash表来辅助查找下标。

桶排序

定义

桶排序是一种思想,不是一个排序方法。不通过比较进行排序而通过多个容器辅助排序的方法。一般对数据有一定的要求。

计数排序

描述

在基本确定知道待排序的数据的范围后,生成一个等大(或稍大)的辅助数组,每有一个数与下标值相等,则将下标对应的值加一,结果数组用辅助数组的下标进行按顺序填充,填充次数为辅助数组下标对应的值。

实现

/**
* max为所有数据中的最大值,arr为待排序数组
*
*/
public void countingsort(int max,int[] arr)
{
	int[] help = new int[max + 1];//生成长度比最大值大一的辅助数组
	for(int i:arr)
	{
		help[i]++;//按arr的值存入辅助数组对应下标的位置
	}
	int i = 0;
	while(i < arr.lenth)
	{
		while(j < max + 1)
		{
			if(help[j]--) arr[i] = j;//如果辅助数组的下标数据不为0,结果数组存入一个下标值
			else j++;//为0则看下一个下标
		}
	}
}

基数排序

描述

十进制通过1~9来当"桶",按个位、十位、百位…的顺序来排序。简单的做法是用队列实现,。

实现

左神比较骚,用的骚方法

/**
* 完全照搬左神的
* arr是待排序数组,L和R分别是要处理的左右边界,digit是arr中最大数的位数
*/
public void radixSort(int[] arr,int L,int R,int digit)
/*例:arr={103,54,89,12,37,114},L = 0,R = 5,digit = 3*/
{
	final int radix = 10;
	int i = 0,j = 0;
	int[] help = new int[R - L + 1];
	//d控制位数,从个位开始循环到最高位
	//为什么从个位(低位)开始循环?
	//因为排到高位时还是会将低位排好序的数打乱,优先按高位的大小排
	for(int d = 1;d < digit;d++)
	{
		int[] count = new int[radix];
		for(i = L;i <= R;i++)
		{
			j = getDigit(arr[i],d);
			count[j]++;
		}
		/*上个循环结束后,count为
		{0,0,1,1,2,0,0,1,0,1}*/
		
		for(i = 1;i < radix;i++)
		{
			count[i] = count[i] + count[i - 1];
		}
		//此时count的含义为,arr中有count[i]个数的倒数第d位数的值小于等于i
		/*上个循环结束后,count为
		{0,0,1,2,4,4,4,5,5,6}*/
		
		//这个循环从右往左遍历,因为我们不能知道count中同一个下标那么多个值左边第一个从哪开始
		//但是我们可以确定右边的第一个,为count[j] - 1的位置
		//把对应值放进辅助数组中
		for(i = R;i >= L;i--)
		{
			j = getDigit(arr[i],d);
			help[count[j] - 1] = arr[i];
			count[j]--;
		}
		/*上个循环结束后,count为
		{0,0,0,1,2,4,4,4,5,5}
		help数组为
		{12,103,54,114,37,89}
		*/
		
		//交接,对高一位的数进行排序
		for(i = L,j = 0;i <= R;i++,j++)
		{
			arr[i] = help[j];
		}
	}
}

/**
* 获取数字n的从右往左数第d位数,没有则为0
* 
*/
public int getDigit(int n,int d)
{
	for(int i = 1;i < d;i++) n /= 10;
	return n % 10;
}

排序总结

时间复杂度额外空间复杂度稳定性
选择排序 O ( N 2 ) O(N^2) O(N2) O ( 1 ) O(1) O(1)
冒泡排序 O ( N 2 ) O(N^2) O(N2) O ( 1 ) O(1) O(1)
插入排序 O ( N 2 ) O(N^2) O(N2) O ( 1 ) O(1) O(1)
归并排序 O ( N ∗ l o g N ) O(N*logN) O(NlogN) O ( N ) O(N) O(N)
随机快排 O ( N ∗ l o g N ) O(N*logN) O(NlogN) O ( l o g N ) O(logN) O(logN)
堆排序 O ( N ∗ l o g N ) O(N*logN) O(NlogN) O ( 1 ) O(1) O(1)
*计数排序 O ( N ) O(N) O(N) O ( M ) O(M) O(M)
%基数排序 O ( N ) O(N) O(N) O ( N ) O(N) O(N)

可以适当的混合使用排序算法提升排序效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Pat晴神宝典是一本关于算法笔记。它由知名的算法专家Pat编写,是一本系统全面的算法学习资料。这本宝典包含了许多不同类型的算法,涉及了各个领域的问题解决方法。 Pat晴神宝典首先介绍了算法的基础知识,如时间复杂度、空间复杂度、数据结构等。然后它深入探讨了各种经典的算法,如排序算法、搜索算法、图算法等。每个算法都有详细的说明和代码实现,以及算法的优缺点和应用场景。宝典还提供了大量的练习题和习题解答,帮助读者巩固所学的算法知识。 Pat晴神宝典不仅仅是一个算法的技术手册,它还讲述了算法的设计思想和解题方法。宝典中有许多实际问题的案例分析,解释了如何使用不同的算法解决实际问题。它还提供了一些常见算法的优化方法和改进思路,帮助读者更好地掌握算法的运用。 总结来说,Pat晴神宝典是一本涵盖了广泛的算法知识的笔记。无论是初学者还是有经验的程序员,都可以从中获得宝贵的算法学习和应用经验。它不仅帮助读者提高解决问题的能力,还培养了读者的算法思维和创造力。无论在学术研究还是工程开发中,这本宝典都是一本不可或缺的参考书。 ### 回答2: PAT晴神宝典是一本算法学习笔记。PAT(Programming Ability Test)是中国程序设计竞赛的一种形式,它旨在提高学生的程序设计能力和算法思维能力。晴神指的是晴天老师,他是一位在算法竞赛界非常有影响力的老师,他编写了《算法笔记》一书。 这本《算法笔记》包含了程序设计竞赛中常用的数据结构和算法的讲解和实践。它主要分为四个部分:基础部分、数据结构、算法以及习题。基础部分主要介绍了程序设计的基本开发环境以及常用的算法思想和技巧,如递归、分治和动态规划等。数据结构部分涵盖了常见的数据结构,如树、图和堆等,以及它们的实现和应用。算法部分介绍了各种算法的设计思想和实现方法,如贪心算法、搜索算法和图论算法等。习题部分提供了大量的练习题,并给出了详细的解题思路和代码。 《算法笔记》以简洁清晰的语言、丰富的例子和详细的讲解,帮助读者掌握算法的基本原理和应用技巧。它不仅适用于想要参加编程竞赛的学生和程序员,也适用于对算法感兴趣的人士。通过阅读该书,读者能够系统地学习和应用算法,提高编程能力和算法思维能力。 总之,PAT晴神宝典是一本覆盖广泛且深入浅出的算法学习笔记,对于学习和应用算法的人士来说,它是一本十分有价值的资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值