题目内容是:给定一个int数组,将正数移动到数组左边,负数移动到数组右边
经过思考,发现了一种比较简单的实现思路,如下:
public static void main(String[] args) {
int[] arr = {8, 6, 4, -3, 5, -2, -1, 0, 1, -9, 1, -1};
int index = -1; //定义指针
for (int i=0; i < arr.length; i++) {
if(arr[i]<0 && index==-1) {//找到最前面的负数
index = i;
}
if(arr[i]>=0 && index!=-1) {//找到了紧跟其后的正数
//交换值
int temp = arr[index];
arr[index] = arr[i];
arr[i] = temp;
i = index; //由于index前面的负数已经与正数交换过,所以将i重置到负数的位置
index = -1; //将指针重置后,重复循环操作
}
}
System.out.println(Arrays.toString(arr));
}
运行结果如下:
然后还有一种更简单的实现思路,拿出来分好类,再放进去:
public static void main(String[] args) {
int[] arr = {8, 6, 4, -3, 5, -2, -1, 0, 1, -9, 1, -1};
List<Integer> list1 = new ArrayList<Integer>();//存储正数
List<Integer> list2 = new ArrayList<Integer>();//存储负数
for (Integer i : arr) {//遍历数组将数据存到对应的集合中
if(i>=0) {
list1.add(i);
}else {
list2.add(i);
}
}
for (int i = 0; i < arr.length; i++) {//正数填充到左边,负数填充到右边
if(i<list1.size()) {
arr[i] = list1.get(i);
}else {
arr[i] = list2.get(i-list1.size());
}
}
System.out.println(Arrays.toString(arr));
}
运行结果如下:
用list集合取代数组进行操作,将负数移动到末尾:
public static void main(String[] args) {
int[] arr = {8, 6, 4, -3, 5, -2, -1, 0, 1, -9, 1, -1};
List<Integer> list = new ArrayList<Integer>();
for (Integer i : arr) { //将数据填充入集合,方便操作
list.add(i);
}
int size = list.size();
for (int i = 0; i < size; i++) {
if(list.get(i)<0) {
list.add(list.remove(i)); //将负数移动到集合尾部
size--; //由于末位已经是负数了,遍历长度减一
i--; //由于此处负数移动到了末尾,所以下标需要回退一步
}
}
for (int i = 0; i < list.size(); i++) { //将数据填充到数组中
arr[i] = list.get(i);
}
System.out.println(Arrays.toString(arr));
}
运行结果如下:
这个是我在网上无意中发现的一种解决思路,不仅快而且巧妙:
public static void main(String[] args) {
int[] arr = {8, 6, 4, -3, 5, -2, -1, 0, 1, -9, 1, -1};
int left = 0; //定义指针,从左侧开始
int right = arr.length-1; // 定义指针,从右侧开始
while(left<right) { //当左指针小于右指针时
if(arr[left]<0 && arr[right]>=0) {//如果左边为负,右边为正,则交换值
arr[left] = arr[left]+arr[right];
arr[right] = arr[left]-arr[right];
arr[left] = arr[left]-arr[right];
}
if(arr[left]>=0) { //如果左数为正,则切换成下一个左数
left++;
}
if(arr[right]<0) { //如果右数为负,则切换成下一个右数
right--;
}
}
System.out.println(Arrays.toString(arr));
}
运行结果如下:
朋友通过改进后得到的,单侧指针法,可以说更加巧妙简单吧:
public static void main(String[] args) {
int[] arr = {8, 6, 4, -3, 5, -2, -1, 0, 1, -9, 1, -1};
for (int i = 0,j = 0; i < arr.length; i++) {
if(arr[i]>=0) { //当前值大于等于0,自己与自己交换。或者当j指针指向负数时,与j指针对应的数交换
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
j++; //大于等于0,指针继续走,遇到负数停下,等待下一个正数然后交换。
}
}
System.out.println(Arrays.toString(arr));
}
运行结果如下:
由此引申出一种单侧指针快排的方法:
public static void main(String[] args) {
int[] arr = {3, 8, 6, 4, -3, 5, -2, -1, 0, 1, -9, 1, -1, 2};
quickSort(0,arr.length,arr);
}
//思路:使得数组中某数的一边大于自己,一边小于自己,当递归到更小的数组范围时,如果每个更小的数组范围内都是有序的,那么整个数组最终是有序的。
public static void quickSort(int low, int high, Integer[] arr) {
if(low >= high) {
return;
}
int j = low;
int lv = arr[low];
for (int i = low; i < high; i++) {
if(arr[i] >= lv) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
j++;
System.out.println(Arrays.toString(arr));
}
}
arr[low] = arr[j-1];
arr[j-1] = lv;
System.out.println(Arrays.toString(arr));
quickSort(low,j - 1, arr);
quickSort(j ,high, arr);
}
//while循环替代for
public static void quickSort(int low, int high, int[] arr) {
if(low >= high) {
return;
}
int i = low,j = low;
int lv = arr[low];
while(i < high) {
if(arr[i] <= lv) {
swap(i, j, arr);
j++;
}
i++;
}
arr[low] = arr[j-1];
arr[j-1] = lv;
quickSort(low,j - 1, arr);
quickSort(j ,high, arr);
}
最终运行结果如下:
[8, 6, 5, 4, 3, 2, 1, 1, 0, -1, -1, -2, -3, -9]