一、基本数据结构之数组
自定义数组(类似ArrayList),数组必须存在在连续的地址空间,实现数组的增删操作。
public class CustomArray {
private int[] array;
// 元素个数
private int size;
private static final String TAG = "CustomArray";
public CustomArray(int capacity) {
array = new int[capacity];
size = 0;
}
public void insert(int index, int element) {
// 判断下标是否合法
if (index < 0 || index > size) {
throw new ArrayIndexOutOfBoundsException("数组越界,超出已有元素范围");
}
// 如果实际元素个数达到数组容量的上限,则进行扩容
if (size >= array.length) {
LogUtils.d(TAG, "我扩容了");
expansionArray();
}
// 数组在内存中占有连续的内存空间,数组插入一个元素,插入位置后面的元素需要依次像后移动一位
/*for (int i = size - 1; i >= index; i--) {
array[i + 1] = array[i];
}*/
if (size - 1 - index >= 0) System.arraycopy(array, index, array, index + 1, size - 1 - index);
array[index] = element;
size++;
}
public int delete(int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("数组越界,超出已有元素范围");
}
int delElement = array[index];
// 需要将元素向前移动一位
/*for (int i = index; i < size - 1; i++) {
array[i] = array[i + 1];
}*/
// 下面这种方式其实是牺牲空间复杂度来提升时间复杂度
if (size - 1 - index >= 0) System.arraycopy(array, index + 1, array, index, size - 1 - index);
size--;
return delElement;
}
public int get(int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("数组越界,超出已有元素范围");
}
return array[index];
}
public void set(int index, int element) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("数组越界,超出已有元素范围");
}
array[index] = element;
}
private void expansionArray() {
// 进行两倍扩容
int[] newArray = new int[array.length * 2];
System.arraycopy(array, 0, newArray, 0, array.length);
array = newArray;
}
public void outArray() {
if (array == null) {
return;
}
for (int element : array) {
LogUtils.d(TAG, "数组元素:" + element);
}
}
public int[] getArray() {
return array;
}
public int getSize() {
return size;
}
}
二、基本数据结构之链表
自定义链表(类似LinkedList),实现增删操作
2.1、定义节点类
public class Node {
public int data;
public Node next;
public Node() {
}
public Node(int data) {
this.data = data;
}
}
2.2、实现链表
public class CustomLinkedList {
// 头结点指针
private Node head;
// 尾节点指针
private Node last;
// 链表长度
private int size;
public void insert(int index, int element) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException("链表越界,超出链表实际范围");
}
Node insertNode = new Node(element);
if (size == 0) {
// 链表长度为0,空链表
head = insertNode;
last = insertNode;
} else if (index == 0) {
// 插入头部
insertNode.next = head;
head = insertNode;
} else if (index == size) {
// 插入尾部
last.next = insertNode;
last = insertNode;
} else {
// 插入中间
// 获取前一个节点
Node preNode = get(index - 1);
Node nextNode = preNode.next;
preNode.next = insertNode;
insertNode.next = nextNode;
}
size++;
}
public Node remove(int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("链表越界,超出链表实际范围");
}
Node removeNode = null;
if (index == 0) {
// 删除头部
removeNode = head;
head = head.next;
} else if (index == size - 1) {
// 删除尾节点
Node preNode = get(index - 1);
removeNode = preNode.next;
preNode.next = null;
last = preNode;
} else {
// 删除中间节点
Node preNode = get(index - 1);
Node nextNode = preNode.next.next;
removeNode = preNode.next;
preNode.next = nextNode;
}
size--;
return removeNode;
}
/**
* 查询
*
* @param index
* @return
*/
public Node get(int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("链表越界,超出链表实际范围");
}
Node tempNode = head;
for (int i = 0; i < index; i++) {
tempNode = tempNode.next;
}
return tempNode;
}
public String outPut() {
StringBuilder builder = new StringBuilder();
Node tempNode = head;
while (tempNode != null) {
builder.append(tempNode.data).append(" ");
tempNode = tempNode.next;
}
return builder.toString();
}
public Node getNode() {
return head;
}
public String outNode(Node node) {
StringBuilder builder = new StringBuilder();
Node tempNode = node;
while (tempNode != null) {
builder.append(tempNode.data).append(" ");
tempNode = tempNode.next;
}
return builder.toString();
}
}
三、反转链表
刚好利用上诉我们自定义的链表实现链表反转
/**
* 反转链表
* @param node
* @return
*/
public Node reverseLinkedList(Node node) {
// 当前节点,将传递进来的头结点赋值给当前节点
Node curNode = node;
// 下一个节点
Node nextNode;
// 前一个节点
Node preNode = null;
while (curNode != null) {
// 取出当前节点的下一个节点赋值给我们定义好的nextNode
nextNode = curNode.next;
// 将当前节点指向前一个节点实现反转
curNode.next = preNode;
// 将当前节点赋值给前一节点
preNode = curNode;
// 移动当前节点到下一个节点
curNode = nextNode;
}
return preNode;
}
调用:
val cusLinkedList = CustomLinkedList()
cusLinkedList.insert(0, 0)
cusLinkedList.insert(1, 1)
cusLinkedList.insert(2, 2)
cusLinkedList.insert(3, 3)
cusLinkedList.insert(4, 4)
cusLinkedList.insert(5, 5)
cusLinkedList.insert(6, 6)
cusLinkedList.insert(7, 7)
cusLinkedList.insert(8, 8)
val node = reverseLinkedList(cusLinkedList.node)
val nodeStr = cusLinkedList.outNode(node)
LogUtils.d(TAG, "反转链表: $nodeStr")
结果:
TestAlgorithmFragment==>: 反转链表: 8 7 6 5 4 3 2 1 0
四、获取数组中出现次数最多的元素
4.1、双层for循环
/**
* 获取数组中出现最多的元素和次数
*
* @param arr
* @return
*/
public int getArrayMostFrequent(int[] arr) {
int mostElement = 0;
int tempCount = 0;
int timeCount = 0;
for (int i = 0; i < arr.length; i++) {
tempCount = 0;
for (int j = 0; j < arr.length; j++) {
if (arr[i] == arr[j]) {
tempCount++;
}
}
if (tempCount > timeCount) {
timeCount = tempCount;
mostElement = arr[i];
}
}
LogUtils.d(TAG, "出现次数最多的元素: " + mostElement + "==>次数: " + timeCount);
return timeCount;
}
4.2、利用map集合,将当前元素作为key,出现次数作为value,然后遍历map集合,value值最大的元素就是出现次数最多的元素
/**
* 获取数组中出现最多的元素和次数
* 使用map优化
*
* @param arr
* @return
*/
public int getArrayMostFrequentForMap(int[] arr) {
Map<Integer, Integer> map = new HashMap<>();
int mostElement = 0;
int count = 0;
int timeCount = 0;
for (int i = 0; i < arr.length; i++) {
if (map.containsKey(arr[i])) {
map.put(arr[i], map.get(arr[i]) + 1);
} else {
map.put(arr[i], 1);
}
}
for (Integer key : map.keySet()) {
if (map.get(key) > timeCount) {
timeCount = map.get(key);
mostElement = key;
}
count++;
}
LogUtils.d(TAG + "使用Map优化", "出现次数最多的元素: " + mostElement + "==>最多元素次数: " + timeCount
+ "元素合并之后遍历次数: " + count);
return timeCount;
}