两个非递减顺序表合并成一个非递减顺序表
- 引入
以下这个例题的描述是关于合并两个有序的数组,然后合并之后同样也是一个非递减的顺序排列
但是我名这里讲的不是顺序表,而是封装成一个顺序表,但是我们这里的顺序表其实底层同样是一个数组,所以解题的思路完全相同,我们接下来要讲的就是“两个非递减顺序表合成的一个非递减的顺序表”。
合并两个有序数组
给你两个按非递减顺序排列的整数数组 nums 1 和 nums 2,另有两个整数 m 和 n ,分别表示 nums 1 和 nums 2 中的元素数目。
请你合并 nums 2 到 nums 1 中,使合并后的数组同样按非递减顺序排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums 1 中。为了应对这种情况,nums 1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。Nums 2 的长度为 n 。
- 我们是合并两个顺序表,只是多了一个封装顺序表的步骤,但是该题目的解法思路是大同小异的。
❤️理清思路
-
非递减顺序表
非递减就是 “增”,而顺序表就是线性表的一种,其逻辑结构是顺序结构,同时其物理结构也和逻辑结构相同的结构,在计算机中存储的物理结构也是连续存储的。
-
题目要求
将两个 “非递减顺序表” 合成一个非递减的顺序表,那么我们在实现这个方法的时候需要传两个 “非递减顺序表”作为参数,然后我们就在方法中对这两个顺序表进行操作。并且最后合成的顺序表同样非递减的顺序表,那么我们在实现方法的时候就必须保证顺序表的顺序一致
-
思路
自定义一个"顺序表"数据结构,然后定义一个方法 merge (),这个方法要求是传进去两个“非递减的顺序表对象” 参数,分别是 list 1 和 list 2;然后我们在方法中重新 new 一个“新的非递减的顺序表对象”newList,然后定义三个指针分别指向这三个顺序表下标为 0 的位置,利用“穿针引线法”,完成合并工作。
-
穿针引线法
我在这里将这种方式描述为 "穿针引线法"是因为真的很形象,但是其实如果是在链表中这样称呼,似乎更加合适。
我们分别让 i 和 j 永远指向即将进行比较大小的数据元素,然后让 k 在新顺序表中永远都指向“索引等于顺序表有效长度“ 的地方,然后等待 i 和 j 比较的结果的数据元素的插入,直到任意一个顺序表遍历完,
如果同时遍历完, 那么合并的工作做完了;如果其中一个顺序表遍历玩,而另外一个没有遍历完,那么就把更长的顺序表直接加到 newList 顺序表中。
综上所述,就完成了两个非递减顺序表的合并工作。
🚀代码实现
package TextReport;
import java.util.Arrays;
public class MyArrayList {
// 存放数据的数组
public int[] elem;
// 记录数组的有效长度
public int usedSize;
// 常量,用来给数组初始化容量
public static final int DEFAULT_CAPACITY = 5;
// 构造方法
public MyArrayList() {
this.elem = new int[DEFAULT_CAPACITY];
}
public MyArrayList(int defaultSize) {
this.elem = new int[defaultSize];
}
// 打印顺序表的方法(顺序表中有几个有效元素就打印几个有效元素)
public void display() {
for (int i = 0; i < usedSize; i++) {
System.out.print(this.elem[i] + " ");
}
System.out.println();
}
// 输入(新增加元素,默认在顺序表的最后一个元素的下一个位置上新增)
public void add(int data) {
try {
if (isFull()) {
elem = Arrays.copyOf(elem, 2 * elem.length);
}
} catch (NegativeArraySizeException e) {
e.printStackTrace();
}
Elem[usedSize++] = data;
}
// 在指定位置索引为 pos 新增元素
Public void addPos (int data, int pos) {
//先判断下标是否合法
Try {
CheckedAddPos (pos);
If (isFull ()) {
Elem = Arrays.CopyOf (elem, 2 * elem. Length);
}
For (int i = usedSize - 1; i > pos; i--) {
Elem[i + 1] = elem[i];
}
Elem[pos] = data;
UsedSize++;
} catch (PosIndexIllegalException e) {
e.getMessage ();
}
}
//判断顺序表中是否包含某个元素
Public boolean contains (int data) {
For (int i = 0; i < usedSize; i++) {
If (data == elem[i]) {
Return true;
}
}
Return false;
}
//返回某个元素的在容器中的索引
Public int indexOf (int find) {
For (int i = 0; i < usedSize; i++) {
If (find == elem[i]) {
Return i;
}
}
Return -1;
}
//获取指定下标 pos 的值
Public int getPos (int pos) {
Int retVal = -1;
//检查 pos 是否合法
Try {
CheckGetPos (pos);
RetVal = elem[pos];
;
} catch (PosIndexIllegalException e) {
e.getMessage ();
}
Return retVal;
}
// 删除第一次出现关键字 key 的方法
Public void remove (int key) {
//先获取第一次出现 key 元素的下标
Int index = indexOf (key);
If (index == -1) {
System.Out.Println ("没有找到你要删除的数据!");
Return;
}
For (int i = index; i < usedSize - 1; i++) {
Elem[i] = elem[i + 1];
}
UsedSize--;
}
/**
* removeAll 方法删除整个顺序表
*/
Public void removeAll () {
Elem = new int[5];
UsedSize = 0;
}
// 判满方法
Private boolean isFull () {
Return usedSize == elem. Length;
}
// 判断顺序表的下标是否合法
Private void checkedAddPos (int pos) {
if (pos < 0 || pos > usedSize) {
Throw new PosIndexIllegalException ();
}
}
// 判断下标 pos 是否合法
Private boolean checkGetPos (int pos) {
if (pos < 0 || pos >= usedSize) {
Return false;
}
Return true;
}
/**
* 获取顺序表的个数
*
* @return 返回数组的大小
*/
Public int size () {
Return usedSize;
}
}
Class PosIndexIllegalException extends RuntimeException {
Public PosIndexIllegalException () {
}
Public PosIndexIllegalException (String msg) {
Super (msg);
}
}
🍔测试程序
我们是在外部的程序 MyArrayListTest 中进行的测试,先准备两个顺序表,然后调用 merge 方法,并把两个参数传进去,然后会返回一个顺序表,我们再继续调用我们封装的 MyArrayList 类当中的 display 方法。
Package TextReport;
Public class MyArrayListTest {
Public static void main (String[] args) {
//准备两个顺序表(非递减的顺序表)
MyArrayList myArrayList 1 = new MyArrayList ();
MyArrayList 1.Add (1);
MyArrayList 1.Add (5);
MyArrayList 1.Add (10);
MyArrayList 1.Add (13);
MyArrayList 1.Display ();
;
MyArrayList myArrayList 2 = new MyArrayList ();
MyArrayList 2.Add (6);
MyArrayList 2.Add (11);
MyArrayList 2.Add (12);
MyArrayList 2.Add (33);
MyArrayList 2.Add (44);
MyArrayList 2.Add (47);
MyArrayList 2.Add (52);
MyArrayList 2.Add (66);
MyArrayList 2.Display ();
;
//调用 merge 方法
MyArrayList mergeArrayList = merge (myArrayList 1, myArrayList 2);
//调用 display 方法
MergeArrayList.Display ();
}
/**
* 合并两个升序的非递减顺序表,并返回新的合成的顺序表
*
* @param list 1 按值非递减顺序表一
* @param list 2 按值非递减顺序表二
* @return 返回一个新的合并了的链表
*/
Public static MyArrayList merge (MyArrayList list 1, MyArrayList list 2) {
MyArrayList newList = new MyArrayList (50);
Int i = 0, j = 0;
While (i < list 1.Size () && j < list 2.Size ()) {
If (list 1. Elem[i] < list 2. Elem[j]) {
NewList. Elem[newList. UsedSize] = list 1. Elem[i];
I++;
NewList. UsedSize++;
} else {
NewList. Elem[newList. UsedSize] = list 2. Elem[j];
J++;
NewList. UsedSize++;
}
}
While (i < list 1.Size ()) {
NewList. Elem[newList. UsedSize] = list 1. Elem[i];
I++;
NewList. UsedSize++;
}
While (j < list 2.Size ()) {
NewList. Elem[newList. UsedSize] = list 2. Elem[j];
NewList. UsedSize++;
J++;
}
Return newList;
}
}
🥰测试结果
💗图文并茂
该图片是合并结束之后的图示,可以形象的看清楚 i ,j,k 这三个“指针是如何“行走的”。
注意:k 下标其实是 usedSize,是顺序表中的用来表示顺序表的有效长度。
🎊视频演示
这个视频简单的演示了我当前举的这个例子是如何进行合并的过程,时常两分钟,希望可以看完,这样可以更好的理解 “如何合并两个非递减的顺序表”。
两个非递减顺序表合并视频演示
点赞+收藏+关注💕