【任务1 - 数组与链表】

这篇博客探讨了数组的动态扩容和增删改查,以ArrayList和LinkedList为例,分析了它们的数据结构特性。同时,介绍了双向链表的增删改查实现,并分享了解决LeetCode上的众数查找和环形链表判断问题的思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        JAVA JDK中List接口下面有两个实现类,分别是ArrayList和LinkedList。其中,ArrayList实现了随机访问的接口,LinkedList实现了Quene的接口。ArrayList是基于数据实现的list,而LinkedList是基于链表实现的list。所以,ArrayList拥有着数组的特性,LinkedList拥有着链表的特性。

问题一:关于数组的动态扩容以及增删改查

我是仿照JDK源码,实现了一下两个功能:

1、实现一个支持动态扩容的数组

2、实现一个大小固定的有序数组,支持动态增删改操作

package codingTest;

public class expandArrayList {
	private Object[] elementData;//数组
	
	private int size;
	
	public int size() {
		return size;
	}
	
	public boolean isEmpty() {
		return size == 0;
	}
	
	//1、数组扩容和数据的拷贝
	private void ensureCapacity() {
		if(size == elementData.length) {
			Object[] newArray = new Object[(size+1)*2];
//			System.arraycopy(elementData, 0, newArray, 0, elementData.length);//老数组copy到新数组这个位置
		    for(int i = 0; i < elementData.length; i++) {
		    	newArray[i] = elementData[i];
		    }
		    elementData = newArray;
		}
	}
	
	//2、实现一个大小固定的有序数组,支持动态增删改操作
	//准备一个空构造器
	public expandArrayList() {
		this(10);//默认数组的长度是10
	}
	
	//准备一个带参构造器
	public expandArrayList(int initalCapacity) {
		if(initalCapacity < 0) {
			try {
				throw new Exception();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		elementData = new Object[initalCapacity];
	}
	
	//获取指定位置的元素
	public Object get(int index) {
		rangeCheck(index);
		return elementData[index];
	}
	
	//改动指定的对象
	public Object set(int index, Object obj) {
		 rangeCheck(index);
		 Object oldValue = elementData[index];
		 elementData[index] = obj;
		 return oldValue;
	}
	
	//删除指定的位置上的数
	public void remove(int index) {
		rangeCheck(index);
		int numMoved = size - index - 1;
		if(numMoved > 0) {
			System.arraycopy(elementData, index+1, elementData, index, numMoved);
		}
		elementData[--size] = null;
	}
	
	//删除指定的对象
	public void remove(Object obj) {
		for(int i = 0; i < size; i++) {
			if(get(i).equals(obj)) {//底层调用的是equals方法,而非==
				remove(i);
			}
		}
	}
	
	//在数组末尾增加元素
	public void add(Object obj) {
		ensureCapacity();
		elementData[size] = obj;
		size++;
	}
	
	//插入指定的对象
	public void insert(int index, Object obj) {
		rangeCheck(index);
		ensureCapacity();
		System.arraycopy(elementData, index, elementData, index+1, size - index);
		elementData[index] = obj;
		size ++;
	}
	
	//数组范围检查
	private void rangeCheck(int index) {
		if(index < 0 || index >= size) {
			try {
				throw new Exception();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		expandArrayList expandList = new expandArrayList(3);
		expandList.add(2);
		expandList.add(32);
		expandList.add(4);
		expandList.add(5);
		System.out.println(expandList.size());
		System.out.println(expandList.get(3));
		System.out.println("------------------------");
		for(int i = 0; i < expandList.size; i++) {
			System.out.println(expandList.get(i));
		}
		System.out.println("------------------------");
		expandList.insert(1, "kkk");
		for(int i = 0; i < expandList.size; i++) {
			System.out.println(expandList.get(i));
		}
	}
}

 

问题二:双向链表的增删改查

我是仿照LinkedList的jdk写的:

package codingTest;

public class Node {
	Node previous;
	Object obj;
    Node next;
	
	public Node(){
		
	}
	
	//构造方法
	public Node(Node previous, Object obj, Node next){
		super();
		this.previous = previous;
		this.obj = obj;
		this.next = next;
	}

	//get与set方法
	public Node getPrevious() {
		return previous;
	}

	public void setPrevious(Node previous) {
		this.previous = previous;
	}

	public Object getObj() {
		return obj;
	}

	public void setObj(Object obj) {
		this.obj = obj;
	}

	public Node getNext() {
		return next;
	}

	public void setNext(Node next) {
		this.next = next;
	}
}
package codingTest;

public class twowayLinkedList {
	private Node first;
	private Node last;
	private int size;
	
	//插入
	public void insert(int index, Object obj) {
		Node temp = ergodicNode(index);
		
		Node newNode = new Node();
		newNode.obj = obj;
		
		if(temp != null) {
			Node former = temp.previous;
			former.next = newNode;
			newNode.previous = former;
			newNode.next = temp;
			temp.previous = newNode;
		}
		size ++;
	}
	
	//删除
	public void remove(int index) {
		rangeCheck(index);
		Node temp = ergodicNode(index);
		
		if(temp != null) {
		    //首先获得上一个节点
			Node former = temp.previous;
			//获得下一个节点
			Node latter = temp.next;
			//下一个节点的先驱节点付给前一个节点的后继结点
			former.next = latter;
			latter.previous = former;
			size--;
		}
	}
	//遍历节点并返回对应index的节点
	public Node ergodicNode(int index) {
		Node temp = null;
		if(first != null) {
			temp =  first;
			for(int i = 0; i < index; i++){
				temp = temp.next;
			} 
		}
		return temp;
	}
	
	//根据索引获取相对应的值
	public Object get(int index) {
		rangeCheck(index);
		Node temp = ergodicNode(index);
		if(temp != null) {
			return temp.obj;
		}
		return null;
	}
	
	//增加操作
	public void add(Object obj) {
		if(first == null) {
			Node n = new Node();
			n.setPrevious(null);
			n.setObj(obj);
			n.setNext(null);
			
			first = n;
			last = n;
		}else {
			//直接往last节点后面增加新的节点
			Node n = new Node();
			n.setPrevious(last);
			n.setObj(obj);
			n.setNext(null);
			
			last.setNext(n);
			last = n;
		}
		size ++;
	}
	
	//获取该List中的元素个数
	public int size() {
		return size;
	}
	
	//检查是否越界
	public void rangeCheck(int index) {
		if(index < 0 || index > size) {
			try {
				throw new Exception();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	//测试类
	public static void main(String[] args) {
		twowayLinkedList myLinkedList = new twowayLinkedList();
		myLinkedList.add("aaa");
		myLinkedList.add("bbb");
		myLinkedList.add("ccc");

		System.out.println(myLinkedList.size());
		System.out.println(myLinkedList.get(1));
	    myLinkedList.remove(1);
		System.out.println(myLinkedList.get(1));
		myLinkedList.insert(1, "ddd");
		System.out.println(myLinkedList.get(1));
		System.out.println(myLinkedList.get(2));
	}
}

问题三:反转单向链表

package codingTest;

public class reverseSingleLink {
	public static class Node {
		public int value;
		public Node next;

		public Node(int data) {
			this.value = data;
		}
	}
	
	public static int reverse(Node head) {
		Node pre = head.next; 
		Node now = head;
		
		if(now != null) {
			Node temp = now.next;
			now.next = pre;
			pre = now;
			now = now.next;
		}
		return pre.value;
	}

//	public static Node reverse(Node head) {
//		if(head == null) {
//			return null;
//		}
//		
//		Node pre = null;
//		Node cur = head;
//		Node reHead = null;
//		
//		//如果当前节点为空,结束循环
//		while(cur != null) {
//			//保存下一个结点,以免丢失
//			Node temp = cur.next;
//			//1.对pre和cur结点的关系进行反转。本来是pre指向cur的,用下面这条代码能够把cur指向pre。
//			cur.next = pre;
//			//2.如果下一个结点为空,那他就是反转链表的头结点
//			if(cur.next == null) {
//				reHead = cur;
//			}
//            //3.上一个结点已经反转完成啦!现在要移动到下一个结点了!
//			pre = cur;
//			cur = temp;
//		}
//		return reHead;
//	}
	
//	
//	static Node reverse(Node head) {
//		Node pre = null;
//		Node temp = null;
//
//		while(head != null){
//			//1.记录下一个结点
//			//2.指针反转
//			temp = head.next;
//			head.next = pre;
//
//			//3.光标移向原链表的下一个结点
//			pre = head;
//			head = temp;
//		}
//
//		return pre;
//	}
	
	public static void main(String[] args) {
		Node node = new Node(1);
		node.next = new Node(2);
		node.next.next = new Node(3);
		node.next.next.next = new Node(4);
		System.out.println(reverse(node));
	}
}

Leetcode 求众数

给定一个大小为 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在众数。

示例 1:

输入: [3,2,3]
输出: 3

示例 2:

输入: [2,2,1,1,1,2,2]
输出: 2
package codingTest;

import java.util.HashMap;
import java.util.Map;

public class majorityNumber_leetcode {
	
	//2、哈希表法
	public static Map<Integer, Integer> countNums(int[] nums) {
        Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
        for (int num : nums) {
            if (!counts.containsKey(num)) {
                counts.put(num, 1);
            }
            else {
                counts.put(num, counts.get(num)+1);
            }
        }
        return counts;
    }
	
	public static int majorityNum(int[] nums) {
		Map<Integer, Integer> counts = countNums(nums);
		Map.Entry<Integer, Integer> majorityEntry = null;
		
		for (Map.Entry<Integer, Integer> entry : counts.entrySet()) {
            if (majorityEntry == null || entry.getValue() > majorityEntry.getValue()) {
                majorityEntry = entry;
            }
        }
		
		return majorityEntry.getKey();
	}
	
	
//方法一:暴力破解法
//	public static int majorityNum(int[] nums) {
//		int majorityCount = nums.length / 2;
//		
//		for(int num : nums) {
//			int count = 0;
//			for(int elem : nums) {
//				if(elem == num) {
//					count += 1;
//				}
//			}
//			
//			if(count > majorityCount) {
//				return num;
//			}
//			
//		}
//		
//		return -1;
//		
//	}
	
	public static void main(String[] args) {
		int[] nums = {2, 3, 4, 4, 5, 1, 4, 4, 4};
		System.out.println(majorityNum(nums));
	}
}

Leetcode 环形链表

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

public boolean hasCycle(ListNode head) {
    Set<ListNode> nodes = new HashSet<>();
    while (head != null) {
        if (nodes.contains(head)) {
            return true;
        } else {
            nodes.add(head);
        }
        head = head.next;
    }
    return false;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值