欢迎来看我的网络日志,交流请加我好友: 919201148。欢迎关注公众号或视频号:蜗牛互联网
Solo  当前访客:3 开始使用

蜗牛学编程

微信搜索「蜗牛互联网」,回复 1024 有惊喜!!! 程序员 | 互联网 | 科技 | Java | 架构 | 职场进阶 | 财富进阶

剑指Offer之十四--调整数组顺序使奇数位于偶数前面

2016-03-27 00:18:30 huayonglun
0  评论    218  浏览

基本解法 保证奇数和奇数,偶数和偶数之间的相对位置不变 遍历每个元素,一旦发现偶数就取出来,让它之后的元素向前移动,把取出来的元素补到最后的空位上 类似插入排序,具体实现是外循环找奇数,内循环将该数之前的偶数移位 public static void reOrderArray(int array[]){ if(array == null || array.length == 0){ return; } for(int i = 1; i < array.length; i++){ int current = array[i]; if(!isEven(current)){ //找到奇数位置 int j = i - 1; //从奇数前一个位置开始 for(; j >= 0 && isEven(array[j]); j--){ //发现偶数就移位 array[j + 1] = array[j]; } array[j + 1] = current; //把奇数插入到偶数前面 } } } 高效解法 相对位置可以改变时,更为高效的解法 维护两个指针,一首一尾 首....

, ,

剑指Offer之十七--合并两个排序的链表

2016-03-27 00:18:30 huayonglun
0  评论    217  浏览

链表结点结构 class ListNode{ int value; ListNode next = null; public ListNode(int value){ this.value = value; } } 题目描述 输入两个单调递增的链表,输出两个链表合成后的链表 当然我们需要合成后的链表满足单调不减规则 递归解法 比较两个链表的开头结点,则可以确定合并后链表的第一个结点 除合并后的结点外,再次比较两个链表的开头结点,则可以确定合并后链表的第二个结点 以此类推,直到所有结点均成为合并后链表中的结点 public static ListNode merge(ListNode list1,ListNode list2) { if(list1 == null){ return list2; } if(list2 == null){ return list1; } ListNode mergeListHead = null; if(list1.value < list2.value){ mergeListHead = list1; mergeListHead.nex....

, , ,

剑指Offer之十六--链表反转

2016-03-27 00:18:30 huayonglun
0  评论    215  浏览

链表结点结构 class ListNode{ int value; ListNode next = null; public ListNode(int value){ this.value = value; } } 题目描述 输入一个链表的头结点,反转该链表并输出翻转后的头结点 代码实现 遍历该链表 保存后一个结点,以防止当前结点的next值更新后链表断开 保存前一个结点,以便当前结点的next值更新为前一个结点 最后一个结点将是反转之后的头结点,保存该结点返回 public static ListNode reverseList(ListNode head) { ListNode reverseListHead = null; ListNode curNode = head; ListNode preNode = null; ListNode nextNode = null; while(curNode != null){ nextNode = curNode.next; if(nextNode == null){ reverseListHead = curNode; }....

, ,

剑指Offer之十五--链表中倒数第k个结点

2016-03-27 00:18:30 huayonglun
0  评论    224  浏览

链表结点结构 class ListNode{ int value; ListNode next = null; public ListNode(int value){ this.value = value; } } 基本解法 遍历两次,第一次确定链表长度,第二次返回第n-k+1个结点,即为所求 注意k不能超过链表长度,代码中要进行判断 public static ListNode findKthToTail(ListNode head,int k){ if(head == null || k <= 0 ){ return null; } ListNode node = head; int nodesNum = 1; while(node.next != null){ nodesNum++; node = node.next; } node = head; int count = 1; while(k <= nodesNum && count != nodesNum - k + 1){ count++; node = node.next; } if(k....

, ,

找出数组中重复最多的数

2016-03-26 05:43:46 huayonglun
0  评论    212  浏览

找出数组中重复最多的数 public static int getRepeatMost(int a[]){ Map<Integer,Integer> map = new HashMap<Integer,Integer>(); //记录每个元素出现的次数 for(int i = 0;i < a.length;i++){ if(map.containsKey(a[i])){ map.put(a[i], map.get(a[i])+1); }else{ map.put(a[i], 1); } } //找出出现次数最多的元素 int most = 0; int result = 0; Set<Integer> set = map.keySet(); Iterator<Integer> it = set.iterator(); while(it.hasNext()){ Integer key = it.next(); Integer value = map.get(key); if(value > most){ most = value....

, ,

格雷码实现

2016-03-26 04:43:46 huayonglun
0  评论    219  浏览

格雷码 格雷码(Gray Code)是一个数列集合,每个数使用二进位来表示 假设使用n位元来表示每个数字,任两个数之间只有一个位元值不同 如果要产生n位元的格雷码,那么格雷码的个数为2^n n位元格雷码是基于n-1位元格雷码产生的 算法 产生 0, 1 两个字符串。 在第一步的基础上,每一个字符串都加上0和1,但是每次只能加一个,所以得做两次。这样就变成了 00,01,11,10 (注意对称)。 在第二步的基础上,再给每个字符串都加上0和1,同样,每次只能加一个,这样就变成了 000,001,011,010,110,111,101,100。 这样就把3位元格雷码生成好了。 如果要生成4位元格雷码,我们只需要在3位元格雷码上再加一层0,1就可以了: 0000,0001,0011,0010,0110,0111,0101,0100,1100,1101,1110,1010,0111,1001,1000. 也就是说,n位元格雷码是基于n-1位元格雷码产生的。 Java实现 public static String[] getGray(int n) { String[] graycode ....

, ,

八大排序算法Java实现

2016-03-26 00:18:30 huayonglun
0  评论    212  浏览

冒泡排序 /* * 冒泡排序 * 相邻元素比较,大的元素往后调 / public static void bubbleSort(int array[]){ for(int i = array.length - 1 ; i >= 0 ; i--){ boolean flag = false; //设置一趟排序是否有交换的标识 for(int j = 0 ; j < i ; j++){ //一趟冒泡排序 if(array[j] > array[j+1]){ swap(array, j, j+1); flag = true; //标识发生了交换 } } if(!flag) break; } } 选择排序 / * 选择排序 * 每个位置选择当前元素最小的 */ public static void selectSort(int array[]){ for(int i = 0 ; i < array.length-1 ; i++){ int minPosition = i; int min = array[i]; for(int j = i+1 ; j <ar....

,

Java安全之对称加密、非对称加密、数字签名

2016-03-21 05:20:01 huayonglun
0  评论    215  浏览

两种加密方式 Java中加密分为两种方式 一个是对称加密 另一个是非对称加密 对称加密是加密和解密的钥匙相同 非对称加密是加密和解密的钥匙不同 对称加密与非对称加密的区别 对称加密称为密钥加密 速度快 加密和解密的钥匙必须相同 只有通信双方才能知道密钥。 非对称加密称为公钥加密 算法更加复杂,速度慢, 加密和解密钥匙不相同 任何人都可以知道公钥,只有一个人持有私钥可以解密。 对称加密解密 /* * 对称加密 */ private static void secretEncrypt() throws Exception { //使用Cipher的实例 Cipher cipher =Cipher.getInstance("AES"); //得到加密的钥匙 SecretKey key =KeyGenerator.getInstance("AES").generateKey(); //初始化加密操作,传递加密的钥匙 cipher.init(Cipher.ENCRYPT_MODE,key); //将加密的钥匙写入secretKey.key文件中 FileOutputStream fosK....

, , ,

TCP中三次握手与四次挥手

2016-03-19 04:43:46 huayonglun
0  评论    215  浏览

TCP(Transmission Control Protocol) 传输控制协议 三次握手 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标示: SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急) Sequence number(顺序号码) Acknowledge number(确认号码) 各个状态的意义如下: LISTEN - 侦听来自远方TCP端口的连接请求; SYN-SENT -在发送连接请求后等待匹配的连接请求; SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认; ESTABLISHED- 代表一个打开的连接,数据可以传送给用户; FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认; FIN-WAIT-2 - 从远程TCP等待连接中断请求; CLOSE-WAIT - 等待从本地用户发来的连接中断请求....

,

排序算法稳定性

2016-03-19 04:43:46 huayonglun
0  评论    214  浏览

定义 排序前后两个相等的数相对位置不变,则稳定 稳定性的好处 从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用 各排序算法的稳定性 堆排序、快速排序、希尔排序、直接选择排序不是稳定的排序算法 基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序是稳定的排序算法 冒泡排序 小的元素往前调或者把大的元素往后调 比较是相邻的两个元素比较,交换也发生在这两个元素之间 稳定排序算法 选择排序 每个位置选择当前元素最小的 在一趟选择中,如果当前元素比一个元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。 举个例子,序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了 不稳定的排序算法 插入排序 已经有序的小序列的基础上,一次插入一个元素 想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置 如果碰见一个和插入元素相 等的,那么插入元素把想插入的元素放在相等元素的后面 相等元素的前后顺序没有改变....

,

MySQL数据库三种常用存储引擎特性对比

2016-03-19 04:43:46 huayonglun
0  评论    217  浏览

什么叫存储引擎? MySQL中的数据用各种不同的技术存储在文件(或内存)中,这些技术中的每一种技术都使用不同的存储机制,索引技巧,锁定水平并且最终提供广泛的不同功能和能力。 在MySQL中将这些不同的技术及配套的相关功能称为存储引擎。 MySQL存储引擎特点 不仅可以同时使用多种存储引擎, 而且每种存储引擎和MySQL之间使用插件方式这种非常松的耦合关系。 MyISAM 特性: 不支持事务:MyISAM存储引擎不支持事务,所以对事务有要求的业务场景不能使用 表级锁定:其锁定机制是表级索引,这虽然可以让锁定的实现成本很小但是也同时大大降低了其并发性能 读写互相阻塞:不仅会在写入的时候阻塞读取,MyISAM还会在读取的时候阻塞写入,但读本身并不会阻塞另外的读 只会缓存索引:MyISAM可以通过key_buffer缓存以大大提高访问性能减少磁盘IO,但是这个缓存区只会缓存索引,而不会缓存数据 适用场景 不需要事务支持(不支持) 并发相对较低(锁定机制问题) 数据修改相对较少(阻塞问题) 以读为主 数据一致性要求不是非常高 最佳实践 尽量索引(缓存机制) 调整读写优先级,根据实际需求....

, ,

事务隔离级别

2016-03-19 04:43:46 huayonglun
0  评论    215  浏览

简述 4个等级的事务隔离级别,在相同数据环境下,使用相同的输入,执行相同的工作,根据不同的隔离级别,可以导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力是不同的。 SERIALIZABLE(串行化) 不会出现任何并发问题,因为它是对同一数据的访问是串行的,非并发访问的; 性能最差; REPEATABLE READ(可重复读)(MySQL) 防止脏读和不可重复读,不能处理幻读问题; 性能比SERIALIZABLE好 READ COMMITTED(读已提交数据)(Oracle) 防止脏读,没有处理不可重复读,也没有处理幻读; 性能比REPEATABLE READ好 READ UNCOMMITTED(读未提交数据) 可能出现任何事务并发问题 性能最好 欢迎关注微信公众号,技术,思维,心理,带给你认知的全方位成长。 你的关注,就是对我最大的肯定,我会努力产出的,我们一起成长~ 本文由 永伦的小屋 原创。 转载请注明作者及出处,本文作者为 永伦的小屋。

,

JVM如何GC

2016-03-19 04:43:46 huayonglun
0  评论    212  浏览

管理对象 引用技术算法 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器的值就加1 当引用失效时,计数器的值就减1,任何时刻计数器为0的对象就是不可能在被使用了 这种算法是很简单的,而且早期很多面向对象语言中都采用这种方式,但是现在主流的Java虚拟机中并没有采用这种方式来管理对象,其原因最主要的原因是它很难解决对象之间的相互循环引用。 可达性分析算法 通过一系列的称谓“GC Roots"的对象作为起始点 从这些节点开始向下搜索,搜索所有走过的路径为引用链,当一个对象到GC Roots没有任何引用链项链时,则证明此对象时不可用的! 上面的这张图,对象object5、object6、object7虽然互相没有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象 注意:Java语言中,可作为GC Roots的对象包括下面几种: 虚拟机栈(栈帧中的本地变量表)中引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象 本地方法栈中JNI(即一般说的Native方法)引用的对象 内存管理 在程序运行过程当中,会创建大量的对象,这些对象,大部....

, ,

JVM的内存区域划分

2016-03-19 04:43:46 huayonglun
0  评论    220  浏览

Java程序具体执行的过程 Java程序具体执行的过程 -- - 首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀) - 由JVM中的类加载器加载各个类的字节码文件 - 加载完毕之后,交由JVM执行引擎执行 - 在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。 - 在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间) 运行时数据区包括哪几部分? 根据《Java虚拟机规范》的规定,运行时数据区通常包括这几个部分: 程序计数器(Program Counter Register) Java栈(VM Stack) 本地方法栈(Native Method Stack) 方法区(Method Area) 堆(Heap) 运行时数据区 运行时数据区的....

, ,

Hashtable与ConcurrentHashMap区别

2016-03-19 04:43:46 huayonglun
0  评论    211  浏览

ConcurrentHashMap的特点 融合了Hashtable和HashMap二者的优势。 Hashtable是做了同步的 HashMap未考虑同步。 HashMap在单线程情况下效率较高 Hashtable在的多线程情况下,同步操作能保证程序执行的正确性 Hashtable每次同步执行的时候都要锁住整个结构 Hashtable与ConcurrentHashMap的锁结构 -- - ConcurrentHashMap正是为了解决这个问题而诞生的 - ConcurrentHashMap锁的方式是稍微细粒度的。 ConcurrentHashMap将hash表分为16个桶(默认值),诸如get,put,remove等常用操作只锁当前需要用到的桶。 - 试想,原来只能一个线程进入,现在却能同时16个写线程进入(写线程才需要锁定,而读线程几乎不受限制,之后会提到),并发性的提升是显而易见的。 ConcurrentHashMap的迭代方式 使用了不同于传统集合的快速失败迭代器的另一种迭代方式,我们称为弱一致迭代器。....

,

Java的wait(), notify()和notifyAll()

2016-03-19 04:43:46 huayonglun
0  评论    208  浏览

官方解释 wait(),notify()和notifyAll()都是java.lang.Object的方法: wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. notify(): Wakes up a single thread that is waiting on this object’s monitor. notifyAll(): Wakes up all threads that are waiting on this object’s monitor. 作用 实现线程间阻塞(Blocking) 控制进程内调度(inter-process communication) 调用前提 必须先获得锁 必须锁定该对象 不获得锁会怎样 public static void main(String[] args) throws InterruptedExcepti....

, ,

HashMap实现原理

2016-03-19 04:43:46 huayonglun
0  评论    215  浏览

数据结构 结合数组和链表的特性,做出的一种寻址容易,插入删除也容易的数据结构——哈希表 最常用的——拉链法,即“链表的数组” HashMap其实也是一个线性的数组实现的,所以可以理解为其存储数据的容器就是一个线性数组。这可能让我们很不解,一个线性的数组怎么实现按键值对来存取数据呢?这里HashMap有做一些处理。 首先HashMap里面实现一个静态内部类Entry,其重要的属性有 key , value, next,从属性key,value我们就能很明显的看出来Entry就是HashMap键值对实现的一个基础bean 我们上面说到HashMap的基础就是一个线性数组,这个数组就是Entry[],Map里面的内容都保存在Entry[]里面。 HashMap的存取实现 HashMap使用的小算法 //存储时: int hash = key.hashCode(); int index = hash % Entry[].length; Entry[index] = value; //取值时: int hash = key.hashCode(); int index = hash % E....

,

JVM类加载过程

2016-03-19 04:43:46 huayonglun
0  评论    215  浏览

类从加载到虚拟机到卸载 整个生命周期包括: 加载(Loading) 连接(Linking) 验证(Validation) 准备(Preparation) 解析(Resolution) 初始化(Initialization) 使用(Using) 卸载(Unloading) 加载 虚拟机主要完成三件事 通过一个类的全限定名来获取定义此类的二进制字节流 将这个字节流所代表的静态存储结构转化为方法区域的运行时数据结构 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区域数据的访问入口 验证 作用 保证Class文件的字节流包含的信息符合JVM规范,不会给JVM造成危害 如果验证失败,就会抛出一个java.lang.VerifyError异常或其子类异常 四个阶段 文件格式验证:验证字节流文件是否符合Class文件格式的规范,并且能被当前虚拟机正确的处理 元数据验证:是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言的规范 字节码验证:主要是进行数据流和控制流的分析,保证被校验类的方法在运行时不会危害虚拟机。 符号引用验证:....

,

linux系统进程间通信的方式

2016-03-19 04:43:46 huayonglun
0  评论    212  浏览

管道( pipe ): 一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 命名管道 (named pipe) : 半双工的通信方式,但是它允许无亲缘关系进程间的通信。 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源 因此,主要作为进程间以及同一进程内不同线程之间的同步手段 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。 消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 共享内存( shared memory ) : 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往....

,
TOP