源码解读之调换字符串顺序——StringBuilder reverse()
来源:互联网 发布:三国志10武将资料数据 编辑:程序博客网 时间:2024/05/22 12:33
1.前言:
今天逛CSDN看见了骆昊的《Java面试题全集(上)》其中第39条:如何实现字符串的反转和替换,如下图所示:
其中说到可以使用String或StringBuffer/StringBuilder中的方法。StringBuffer和StringBuilder都继承了AbstractStringBuilder抽象类,该类提供了一个reverse()方法
现在我们就来具体看一下reverse方法
先上源码,如下:
/** * Causes this character sequence to be replaced by the reverse of * the sequence. If there are any surrogate pairs included in the * sequence, these are treated as single characters for the * reverse operation. Thus, the order of the high-low surrogates * is never reversed. * * Let n be the character length of this character sequence * (not the length in {@code char} values) just prior to * execution of the {@code reverse} method. Then the * character at index k in the new character sequence is * equal to the character at index n-k-1 in the old * character sequence. * *Note that the reverse operation may result in producing * surrogate pairs that were unpaired low-surrogates and * high-surrogates before the operation. For example, reversing * "\u005CuDC00\u005CuD800" produces "\u005CuD800\u005CuDC00" which is * a valid surrogate pair. * * @return a reference to this object. */ public AbstractStringBuilder reverse() { boolean hasSurrogates = false; int n = count - 1; for (int j = (n-1) >> 1; j >= 0; j--) { int k = n - j; char cj = value[j]; char ck = value[k]; value[j] = ck; value[k] = cj; if (Character.isSurrogate(cj) || Character.isSurrogate(ck)) { hasSurrogates = true; } } if (hasSurrogates) { reverseAllValidSurrogatePairs(); } return this; } /** Outlined helper method for reverse() */ private void reverseAllValidSurrogatePairs() { for (int i = 0; i < count - 1; i++) { char c2 = value[i]; if (Character.isLowSurrogate(c2)) { char c1 = value[i + 1]; if (Character.isHighSurrogate(c1)) { value[i++] = c1; value[i] = c2; } } } }
首先我们看一下第一个,也就是主要的reverse方法
public AbstractStringBuilder reverse() { boolean hasSurrogates = false; int n = count - 1; for (int j = (n-1) >> 1; j >= 0; j--) { int k = n - j; char cj = value[j]; char ck = value[k]; value[j] = ck; value[k] = cj; if (Character.isSurrogate(cj) || Character.isSurrogate(ck)) { hasSurrogates = true; } } if (hasSurrogates) { reverseAllValidSurrogatePairs(); } return this; }
第一行
boolean hasSurrogates = false;结合
if (Character.isSurrogate(cj) || Character.isSurrogate(ck)) { hasSurrogates = true; } if (hasSurrogates) { reverseAllValidSurrogatePairs(); }
主要是为了实现特殊字符的处理。这一块就不详细说了,可自行回去看一下Character.isSurrogate()方法
接下来我们来具体看一下实现反转字符串的核心代码
int n = count - 1; for (int j = (n-1) >> 1; j >= 0; j--) { int k = n - j; char cj = value[j]; char ck = value[k]; value[j] = ck; value[k] = cj; if (Character.isSurrogate(cj) || Character.isSurrogate(ck)) { hasSurrogates = true; } }其中count为字符串的长度,value为char数组,按顺序存放了字符串的所有字符
下面就是具体的实现的原理
//比如我们有一个数组如下 char[] arr = {1,2,3,4,5,6,7,8,9}; //5是中间数,所以位置不用动。将4和6调换位置,将3和7调换位置,将2和8调换位置,将1和9调换位置。这样就实现了顺序的调转 //这边又是如何找到中间数的呢,看下面的三行代码(只是截取片段,所以不标准) int n = count - 1 for (int j = (n-1) >> 1; j >= 0; j--) { int k = n - j; //第一行代码,获取数组下标最大值 /** * 第二行:int j = (n-1) >> 1; * 我们以前如何获取需要调换的两个数?比如有10个数, * 第一种:判断数数量能不能被2整除,即n%2==0。如果可以,需要调换的两个数就是n/2和n+1-(n/2)。如果不行则左边的数为(n-1)/2,右边的为n+1-(n-1)/2 * 第二种:直接用int的特性,左边的数(int)(n/2),右边n+1-((int)(n/2)) * 第三种就是位移,n >> 1是什么意思?我们换成第一种写法说明一下位移运算大家就知道了 * 比如这样一个位移表达式 n >> x,把一个数n右位移x位 * 转换后就是(n-n%2^x)/2^x,这时候如果像右位移1位则变为(n-n%2)/2 * 这时候就比较清楚了:(n-n%2)能被2整除就取n,不能整除就取n-1 * 然后除以2得到的就是左边的数,右边的数就是n+1-左边 * 因为数组下标从0开始,我们刚刚所说的都是从1开始,所以整体减1 * 所以左边边:j = (n-1) >> 1 ; 右边 k = n - j; * */
剩下的元素交换顺序我就不说了,就是交换位置。
最后改造一下,封装成自己的工具类,不需要使用AbstractStringBuilder,直接调用方法,传入字符串就可以
public class Reversal { public static String reverse(String str) {if(str == null || str.length()<=1)return str;char[] value = str.toCharArray();int count = value.length; boolean hasSurrogates = false; int n = count - 1; for (int j = (n-1) >> 1; j >= 0; j--) { int k = n - j; char cj = value[j]; char ck = value[k]; value[j] = ck; value[k] = cj; if (Character.isSurrogate(cj) || Character.isSurrogate(ck)) { hasSurrogates = true; } } if (hasSurrogates) { reverseAllValidSurrogatePairs(count, value); } return String.copyValueOf(value); } /** Outlined helper method for reverse() */ private static void reverseAllValidSurrogatePairs(int count, char[] value) { for (int i = 0; i < count - 1; i++) { char c2 = value[i]; if (Character.isLowSurrogate(c2)) { char c1 = value[i + 1]; if (Character.isHighSurrogate(c1)) { value[i++] = c1; value[i] = c2; } } } } public static void main(String[] args) {String str = "abcdefghijk你好。:‘,./;lmnopqrstuvwxy";System.out.println(reverse(str)); }}
时间也比较赶,也是刚开始写博客,写的不好的地方请大家见谅。
- 源码解读之调换字符串顺序——StringBuilder reverse()
- java源码解读之String,StringBuilder,StringBuffer
- Spring源码解读顺序
- leetcode——Reverse Words in a String 旋转字符串中单词顺序(AC)
- 源码解读之Intent解读
- Qwt源码解读之区间类——QwtInterval
- Qwt源码解读之标尺相关类——QwtScaleMap
- Qwt源码解读之标尺相关类——QwtScaleDiv
- Qwt源码解读之棒图类——QwtPlotBarChart
- Qwt源码解读之列矩形类——QwtColumnRect
- 源码解读----之-----KMeans
- AMPS:字符串操作源码解读
- mssql 字符串颠倒顺序函数 reverse()应用
- kubernetes源码解读——源码结构
- TL之StringBuilder构建字符串
- Java字符串之String StringBuilder
- Java字符串处理之StringBuilder
- 字符串 —— String?StringBuffer?StringBuilder?
- 阿里热修复学习总结
- Altium Designer 使用笔记 总结
- 前端之路随笔小记——height:100%
- 机器学习(3)——支持向量机(Support Vector Machine)
- ODOO技术在教育行业软件上的应用
- 源码解读之调换字符串顺序——StringBuilder reverse()
- 【安全牛学习笔记】拒绝服务介绍、DoS分类、个人DoS分类方法
- 详解正向代理和反向代理
- PicrossMadness
- Docker下的Kafka学习之一:制作集群用的镜像文件
- Nodejs学习(六)--异步流控制
- 数据库
- LeetCode Exercise 5: Trapping Rain Water
- 7-9 龟兔赛跑(20 分)