练习题

Posted You295

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了练习题相关的知识,希望对你有一定的参考价值。

练习题(一)

一:列举java的常用容器(集合)

常用的容器主要分为以下两种类型:
1:collection:是一个独立元素的序列,这些元素都服从一条或者多条规则;List必须按照插入的顺序来保存元素,set中不能够有重复的元素;queue按照排队的规则来确定对象产生 的顺序。

1)list接口常用类有ArrayList,LinkedList,Vector和Stack
       a)ArrayList类:基于数组的数据结构,不同步,线程不安全,查询的效率高。
       b)LinkedList类:基于链表的数据结构,允许null元素;增加,删除,修改元素方面效率比ArrayList高。  LinkedList还可被用作堆栈(stack),队列(queue)还有双向队列。
       c)Vector:非常类似于ArrayList,但是Vector是同步的
       d)Stack:继承与Vector,实现了一个先进后出的堆栈。      
       
2) Set接口:set容器类主要有HashSet和TreeSet等。元素不能够重复,都实现了java.until.Set接口                                                                                                                                                                                                            
       a)  HashSet类:不能保证集合中元素的顺序,允许包含值为null的元素,但是最多只能有一个null元素。
       b)TreeSet类:是set的一种变体,可以实现排序等功能的集合,它在将对象元素添加到集合中时会自动按照某种比较规则将其插入到有序的对象序列中,并保证该集合元素组成按 升序 排列。

2:map:一组成对的 ”键值对“ 对象,允许使用键来查找值。
a) Map集合接口:Map没有继承Collection接口,Map提供key到value的映射。一个map中不能包含相同的key,每个key只能映射到一个value。

二:List和Set的区别,不可重复是什么意思?

1)List和Set都是继承自collection这个集合中,而set中的元素是无序的并且不可重复的,只能存放一个null;而List中的元素是有序的,可以重复,可有多个null。
2)set这个接口的实现类有HashSet和TreeSet,HashSet它的底层实现是HashMap中的key作为存放元素的位置,而在hashmap中不能包含相同的key,故不可重复。

三:HashMap是否线程安全,如果想用线程安全的HashMap应该怎么做?

1:HashMap不是线程安全的。
2:可以有三种方法实现让HashMap变得线程安全;
1)替换成HashTable,HashTable通过对整个表上锁实现线程安全,故因此效率很低。
2)使用Collections类的synchronizedMap方法进行包装。方法为:

public static <k,v>Map<k,v>
synchronizedMap(Map<k,v>m)  //返回由指定映射支持的同步(线程安全)的映射

3:使用ConcurrectHashMap,它会使用分段锁来保证线程的安全。

前两种方式获得的线程安全的HashMap在读写数据的时候会对整个容器进行上锁,而第三种不需要对整个容器上锁,它只需要锁住要修改的部分即可。

四:编写一个单利例模式,常见的单例模式有哪些,将其列举出来

一共有三种:饿汉式,懒汉式,枚举法
1)懒汉式:线程不安全,需要对getInstance方法进行改造—<1> 可加同步锁synchronized; <2> 用重入锁—ReentrantLock

public class eHan 

	/**
	 * 饿汉式
	 */
	private static eHan instance;

	public eHan()  // 构造方法

	

	public static eHan getInstance() 
		if (instance == null) 
			instance = new eHan();
		
		return instance;
	

2)饿汉式:在类创建的同时就已经创建好了一个静态的对象供系统使用,以后也不再改变,所以天生的线程安全。

public class LanHan 

	private static LanHan instance = new LanHan();

	public LanHan()  // 构造方法

	

	private static LanHan getInstance() 
		return instance;
	

3)枚举法:代码简洁,自动支持系列化机制,绝对防止多次实例化。

public enum MeiJu 
	INSTANCE;


五:有哪些排序算法,写出快速排序的实现

1:排序有:冒泡排序,选择排序,插入排序,希尔排序,归并排序,快速排序,堆排序,计数排序,桶排序,基数排序。
2:快排的实现如下:

public class quickly 
	/**
	 * 测试
	 */
	public static void main(String[] args) 
		int[] arr =  5, 2, 7, 98, 23, 65, 122, 63 ;
		quickSort(arr, 0, arr.length - 1);

		// 遍历数组打印出来
		for (int i = 0; i < arr.length; i++) 
			System.out.print(arr[i] + " ");
		
	

	/**
	 * 快排的方法
	 */
	public static void quickSort(int[] arr, int left, int right) 
		// 如果左边索引大于右边的索引则不合法,直接return
		if (left > right) 
			return;
		
		// 定义变量保存基准数
		int base = arr[left]; // 基准数一直在最左边
		// 定义变量i,指向最左边
		int i = left;
		// 定义变量j,指向最右边
		int j = right;
		// 当i和j不相遇时,在循环中检索
		while (i != j) 
			// j从右向左检索,检索到比基准数小的就停下
			// i从左向右检索,检索到比基准数大的就停下
			while (arr[j] >= base && i < j) 
				j--; // j从右往左移动
			
			// i从左往右
			while (arr[i] <= base && i < j) 
				i++;
			
			// 到这里i与j都停下了,交换他们两个位置的元素
			int tmp = arr[i];
			arr[i] = arr[j];
			arr[j] = tmp;
		
		// 如果while循环条件不成立,说明i和j相遇了,就交换基准数这个元素和相遇位置的元素

		// 先将相遇位置的元素赋值给基准数这个位置的元素
		arr[left] = arr[i];
		// 再把基准数赋值给相遇位置的元素
		arr[i] = base;

		// 此时基准数归位,左边的都比他小,右边的都比他大,先排左边,在排右边,方法和上边的一样,可以直接调用
		quickSort(arr, left, i - 1);
		quickSort(arr, i + 1, right);
	


测试结果:

六:给一个二叉树,使用递归和非递归写出前序,中序,后序遍历以及广度优先

1:前序遍历
1)递归:

public void qianXuA(TreeNode root) 
		if (root == null) 
			return;
		
		System.out.println(root.val);
		qianXuA(root.left); // 左子树
		qianXuA(root.right); // 右子树
	

2)非递归:

public List<Integer> qianXuB(TreeNode root)
		List<Integer> list = new ArrayList<>(); //创建返回集合
		Stack<TreeNode> stack = new Stack<>(); //创建辅助队列
		if(root==null)  //特殊情况为空树时
			return list;
		
		stack.push(root); //入栈
		while(!stack.isEmpty())  //终止条件为辅助栈为空时
			TreeNode tmp = stack.pop(); //将元素出栈操作
			list.add(tmp.val); //加入集合中
			if(tmp.right!=null)   //右子树入栈
				stack.add(tmp.right); 
			else if(tmp.left!=null)  //左子树入栈
				stack.add(tmp.left)
			
		
		return list;
	

2.中序遍历
1)递归:

public class zhongXuA 
	public void zhongXuA(TreeNode root) 
		if (root == null) 
			return;
		
		zhongXuA(root.left); // 左子树
		System.out.println(root.val); // 根节点
		zhongXuA(root.right); // 右子树
	

2)非递归:

	public List<Integer> zhongXu(TreeNode root) 
		List<Integer> list = new ArrayList<Integer>();
		Stack<TreeNode> stack = new Stack<TreeNode>();
		TreeNode tmp = root;
		while (tmp != null || !stack.isEmpty()) 
			while (tmp != null) 
				stack.push(tmp); // 根节点入栈
				tmp = tmp.left; // 左子树
			
			tmp = stack.pop(); // 出栈
			list.add(tmp.val);
			tmp = tmp.right;// 右子树
		
		return list;
	

3.后序遍历:
1)递归:

public void houXu(TreeNode root) 
		if (root == null) 
			return;
		
		houXu(root.left); // 左子树
		houXu(root.right); // 右子树
		System.out.println(root.val); // 根节点
	

2)非递归:

public List<Integer> houXu(TreeNode root) 
		List<Integer> list = new ArrayList<Integer>();
		Stack<TreeNode> stack = new Stack<>();
		TreeNode tmp = root;
		while (tmp != null || !stack.isEmpty()) 
		
		while (tmp != null) 
			stack.push(tmp);
			tmp = tmp.left;
		
		TreeNode t = stack.peek(); // 获得栈顶元素
		if (t.right == null) 
			list.add(stack.pop().val);
		 else 
			tmp = tmp.right;
			t.right = null;
		
		return list;
	

4.广度优先:

public void guangDu(TreeNode root) 
		if (root == null) 
			return;
		
		Queue<TreeNode> q = new LinkedList<>();
		q.add(root);

		while (!q.isEmpty()) 
			TreeNode tmp = q.poll();
			System.out.println(tmp.val);
			if (tmp.left != null) 
				q.offer(tmp.left);
			
			if (tmp.right != null) 
				q.offer(tmp.right);
			
		
	

七:数据库的事务的四大特性以及数据库的隔离级别

1.数据库事务的四大特性
1)原子性:事务中包含的所有操作要么都去做,要么就都不做。
2)一致性:数据库的事务操作在操作前后都必须满足约束原则。
3)隔离性:多个用户共同访问数据库时,数据库为每个用户开启的事务之间互不干扰。
4)持久性:事物一旦被提交,那么它对数据的操作就是永久的,就算数据库发生异常,也不会对其产生影响。

2.数据库的隔离级别:
1)读未提交:在其中一个事务中,可以读到其他事务没有提交的数据变化。会产生脏读现象,并且也没有办法限制不可重复读和幻读。
2)读已提交:在其中的一个事务中可以读取到其他事务已经提交的数据变化。可防止脏读现象,无法限制不可重复读和幻读。
3)可重复读:在其中一个事务中直到事务结束之前,都可以反复的读到事务刚开始看到的数据,并且一直不会发生变化,有效的防止了脏读和不可重复读。
4)串行:在多个事务运行时,只有等一个事务运行完了,才能运行其他的事务。

八:TCP的三次握手和四次挥手

三次握手
1)第一次握手:客户端执行connect函数,向服务端发送连接请求报文段,tcp报文首部 SYN=1,等待服务端的回答。
2)第二次握手:服务端收到请求后,若同意连接,则向客户端发送确认,确认报文段中SYN=1,ACK=1、
3)第三次握手:客户端收到服务端的确认信息后,还要给服务端发送确认,将确认报文段 ACK=1。

四次挥手:
1)第一次挥手:客户端向服务端发送连接释放报文段,停止发送数据,将FIN=1。
2)第二次挥手:服务端收到连接释放报文段后发出确认信息,将确认报文段首部ACK置为1。此时服务器处于半关闭状态,客户端已经没有数据发送了,如果服务端要发送数据,客户端还可以接收,故服务端到客户端这条路还没有关。
3)第三次挥手:服务端没有数据要发送了,就会通知tcp释放连接,向客户端发出链接释放报文段将FIN置为1,此时服务端就进入了最后的等待确认状态。
4)第四次挥手:客户端收到请求后报文段后,需要对此最后发出确认,将ACK置为1,客户端进入了时间等待状态。

经过时间等待计时器设置的2MSL 后,客户端才进入关闭状态,MSL称为 最长报文寿命,即报文段的最长存活时间。

九:GET和POST的区别,除了它两还有那些?

get和post的本质就是tcp链接,并无差别,但是由于HTTP的规定和浏览器,服务器的限制,导致他们在应用的过程中出现了区别。

区别: 1):get产生一个tcp数据包,对于get方式的请求,浏览器会把http header和data一起发送出去,服务器响应200(返回数据); 而post产生两个tcp数据包,浏览器会先发送header,服务器响应100 continue,浏览器继续发送data,服务器响应200结束;(当然也不是所有的浏览器都会在post中发送两次包)
2)get方法的参数会放在URL中,而post是将参数放在HTTP打包的request body中。
3)get方法提交的数据大小有限制,因为浏览器对URL的长度有限制;而post方法提交的数据大小是没有限制的。
4)安全性方面get比post更加的不安全,因为它是将参数放在url中的 ,但是对于post来说提交的参数也可以通过F12来查看,在安全性方面差别并不是很大。
5)get是可以缓存的,但是post则不可以。
6)get请求页面后退时,不会产生影响,;post请求页面后退时,会重新提交请求。

十:equals和 == 的区别?

1. ==(比较运算符)

1.比较基本类型:判断8种基本的数据类型之间的值是否相等;(long , int , byte , short , float , double , boolean , char )

2.比较引用类型:是比较堆内的内存地址是否相等,,如果重新new出一个引用类型的对象的时候,那么就会重新的分配内存地址,使用 == 比较就会直接返回false

2.equals(继承于object类)

1.比较引用类型:在默认的时候,equals它比较的也是内存地址是否相等;但是对 equals 方法重写后就是看两个比较对象的hash值是否一致,只有hash值相同时系统才会去判定他们两个对象是否相等。
两个对象的hash值相等时,equals值不一定相同,,但是equals值相同时,hash值一定相等

以上是关于练习题的主要内容,如果未能解决你的问题,请参考以下文章

练习题proj1 判断二叉树子树和是否为指定的值

二叉树基础练习

数据结构之二叉树基础OJ练习另一颗树的子树

算法练习5---快速排序Java版

树形结构 习题

数据结构——二叉树的基础练习题(单值二叉树,翻转二叉树,相同的树,对称二叉树,另一颗子树,二叉树的前序遍历)