Tham chiếu trong Java

Mình có đoạn code xóa một phần tử tại viTri bất kỳ bên C++:

void xoaPhanTu(int a[], int &n, int viTri)
{
	for(int i = viTri; i < n - 1; i++)
		a[i] = a[i + 1];
	n--;
}

Mỗi lần xóa một phần tử n sẽ giảm đi 1 nhờ có tham chiếu tới n
Vậy trong JAVA mình muốn làm tương tự như trên để giảm n đi 1 mỗi lần gọi hàm xóa thì phải làm như thế nào?

tạo 1 lớp chứa mảng a và int n rồi viết method xóa phần tử

3 Likes

Không may là trong Java không có tham chiếu cho kiểu nguyên thủy.
RẤT MAY là trong Java đã có thuộc tính length của mảng rồi (không cần n như trong C/C++ nữa) :smiling_imp:

3 Likes

Bạn có thể demo cho mình được không? Mình mới học java nên không hiểu ý bạn lắm :((

Sử dụng thuộc tính length trong trường hợp này như thế nào vậy anh?

Trong trường hợp bạn muốn “xóa” một phần tử bằng cách tạo mảng mới thôi.

Còn muốn xóa như đoạn C++ trên thì làm như @tntxtnt đã nói.
Tạo 1 lớp chứa mảng (a) và số phần tử (n).

public class Arr{
   public int[] arr;
   public int num;
   public Arr(int[] a, int n){
      arr = a;
      num = n;
   }
   //...
}

//...
void xoaPhanTu(Arr a, int viTri)
{
	for(int i = viTri; i < a.num - 1; i++)
		a.arr[i] = a.arr[i + 1];
	a.num--;
}
//...
int n = ... // Số phần tử
int[] a = ... // Mảng
Arr x = new Arr(a,n);
xoaPhanTu(x, 2);
3 Likes

Mảng sinh ra vốn không phải để xoá phần tử, nên length không thể thay đổi như n.
Bạn xoá mảng kiểu đó, bản chất nó vẫn là cái mảng ban đầu, n thay đổi không ảnh hưởng kích thước mảng thật. length của Java cũng vậy.

Nếu như đối với kiểu dữ liệu danh sách mà bạn muốn thay đổi kích thước, trong Java bạn nên sử dụng List

List<Integer> a = new ArrayList<>();
a.add(15);//Thêm phần tử 15 vào cuối cùng danh sách
a.add(2, 10);//Thêm phần tử 10 vào vị trí thứ 3 danh sách
a.remove(3);//Xoá phần tử ở vị trí thứ 4
a.remove(x -> x == 5);//Xoá những phần tử có giá trị bằng 5

Còn nếu bạn thực sự muốn dùng mảng, bạn phải khởi tạo mảng mới:

int[] xoaPhanTu(int[] a, int viTri)
{
	int[] output = new int[a.length - 1];
	for (int i = 0; i < viTri; i += 1)
		output[i] = a[i];
	for (int i = viTri; i < a.length - 1; i += 1)
		output[i] = a[i + 1];
	return output;
}
a = xoaPhanTu(a, 5);
4 Likes

Hay quá :blush: Em cám ơn anh.

Đoạn sau trích từ source code ArrayList.java trong JDK 8. remove(int index) xoá phần tử tại vị trí index. Lý do mình chọn ArrayList<T> vì nó có private field là Object[] elementData, giống với code C++ của bạn.

public E remove(int index) {
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                            numMoved);
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

Có vài chi tiết trong này:

  • elementData là native array của Java.
  • size là số lượng phần tử hiện có trong elementData
  • rangeCheck() là method kiểm tra điều kiện 0 <= index < size
  • modCount là số lần elementData thay đổi (thêm, xoá, sửa)
  • System.arraycopy(src, srcIndex, dest, destIndex, length) là native method, thực hiện bởi JVM, copy length phần tử của native array src bắt đầu từ srcIndex sang native array dest bắt đầu từ destIndex.

Thứ tự thực hiện xoá phần tử ở vị trí index:

  • Kiểm tra index bằng method rangeCheck()
  • Vì đang thực hiện xoá phần tử, nên modCount tăng lên 1
  • Gán giá trị cần xoá elementData[index] sang oldValue
  • numMoved là số phần tử từ vị trí index đến size - 2, hoặc số phần tử trong (index+1, size-1)
  • System.arraycopy() thực hiện di chuyển (copy) numMoved phần tử ở (index+1, size-1) sang (index, size-2).
  • Gán phần tử cuối cùng elementData[size-1] giá trị null.
  • Giảm size đi 1, hay chiều dài mảng giảm đi 1.
  • Trả về giá trị oldValue là phần tử đã xoá.

Source Code (467-489)

5 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?