第一天
1.设计一个动态数组
import java.util.Arrays;
public class MyArr {
private int[] data;
//表示当前数组中已经存储的元素个数
private int size;
//通过构造方法,传入一个长度为length的整形数组
//data数组初始化,产生一个新的数组对象
public MyArr(int length) {
this.data = new int[length];
}
//在数组末尾添加一个值为val的元素
public void add(int val) {
data[size]= val;
size ++;
//判断数组是否已满,是否需要扩容
if (size == data.length){
grow();
}
}
//在数组的index索引位置添加一个值为val的元素
public void add(int index ,int val) {
//首先要判断索引位置是否合法
if (index < 0 || index > size) {
//错误输出
System.err.println("索引非法,请重新输入");
}
int ret = data[index];
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = val;
size++;
if (size == data.length) {
grow();
}
}
//查询 查询当前动态数组中第一个值为val的元素索引
public int getByValue(int val){
for (int i = 0; i < size; i++) {
if (data[i] == val){
return i;
}
}
//循环走完,还未找到val,说明数组中不存在
return -1;
}
//查询 查询当前动态数组中是否包含值为val的元素
public boolean contains(int val){
return getByValue(val) != -1;
}
//查询当前动态数组中索引为index的元素值
public int get(int index){
if(index < 0 || index >= size){
System.err.println("索引非法,请重新输入");
return -1;
}
return data[index];
}
//修改 修改index位置的元素为新的值newval,返回修改前的值
public int set(int index, int newval) {
if(index < 0 || index >= size){
System.err.println("索引非法,请重新输入");
return -1;
}
int ret = data[index];
data[index] = newval;
return ret;
}
//修改 修改第一个值oldVal 的值,更改为新的值 newVal ,返回是否修改成功
public boolean setVal(int oldVal, int newVal){
//利用写好的getByValue方法,判断oldVal是否存在
int index = getByValue(oldVal);
if (index != -1){
data[index] = newVal;
return true;
}
return false;
}
//删除 删除索引为index 对应的元素, 返回删除前的元素
public int remove (int index){
if(index < 0 ||index >= size){
System.err.println("索引非法,请重新输入");
return -1;
}
int ret = data[index];
for (int i = index; i < size-1 ; i++) {
data[i] = data[i+1];
}
size--;
return ret ;
}
//删除 删除数组的头元素
public int removeFirst(){
return remove(0);
}
//删除 删除数组的尾元素
public int removeLast(){
return remove(size-1);
}
//删除 删除第一个值为val的元素,返回是否删除成功
public boolean removeByValOnce(int val) {
for (int i = 0; i < size; i++) {
if (data[i] == val){
remove(i);
return true;
}
}
return false;
}
//删除 删除数组中所有值为val的元素
public void removeAllVal(int val){
for (int i = 0; i < size; i++) {
//内层循环也要保证索引的合法性
while (i < size && data[i] == val){
remove(i);
}
}
}
//扩容方法是私有的,因为对程序的使用者来说,根本不知道MyArr类中有一个数组
//数组的扩容方法对外部也是不可见的
private void grow() {
this.data = Arrays.copyOf(data,data.length*2);
}
public String toString(){
String ret = "[";
for (int i = 0; i < size; i++) {
ret += data[i];
if(i != size-1){
ret += ", ";
}
}
ret += "]";
return ret;
}
}
测试
public class TestMyArr {
public static void main(String[] args) {
MyArr arr=new MyArr(3);
System.out.println("扩容前数组长度为:"+arr.data.length);
arr.add(1);
arr.add(2);
arr.add(2);
arr.add(3);//添加元素
System.out.println(arr);
arr.remove(0);//根据下标删除
System.out.println(arr);
arr.removeAllVal(2);//删除所有为2的数
System.out.println(arr);
System.out.println("扩容后数组长度为:"+arr.data.length);
}
}
结果为:
扩容前数组长度为:3
[1, 2, 2, 3]
[2, 2, 3]
[3]
扩容后数组长度为:6
2.设计一个栈
package Howe;
import java.util.Arrays;
public class Stack {
private Object[] data;
private int size;
private int capacity;
public Stack() {
// 默认创建一个10容量的栈
this.capacity = 10;
data = new Object[this.capacity];
}
public Stack(int capacity) {
this.capacity = capacity;
data = new Object[this.capacity];
}
//进栈一个元素
public void push(Object e){
// 先判断栈是否已经满了
if (this.isFull()) {
// 扩容
// 扩容的规则是原有容量的1.5倍
int length = this.capacity + (this.capacity >>> 1);
this.resize(length);
} else {
this.data[size++] = e;
}
}
// 判断是否存满
private boolean isFull() {
return this.capacity == this.size;
}
// 扩容或缩容容器的大小
private void resize(int len){
this.data = Arrays.copyOf(this.data, len);
this.capacity = len;
}
// 判断栈是否为空
public boolean isEmpty(){
return this.size == 0;
}
// 出栈一个元素
public Object pop(){
if (this.isEmpty()) {
throw new RuntimeException("对不起,栈中已经没有元素了");
}
return this.data[--this.size];
}
// 查看栈顶元素
public Object peek(){
return this.data[this.size - 1];
}
// 获取栈中元素的个数
public int size(){
return this.size;
}
// 清空栈
public void clear(){
this.size = 0;
}
// 返回栈的字符串形式
public String toString(){
return Arrays.toString(Arrays.copyOf(this.data, this.size));
}
// 对比两个栈是否相等
@Override
public boolean equals(Object o) {
Stack s = (Stack) o;
if (this.size != s.size()) {
return false;
}
for (int i = 0; i < s.size() ; i++) {
if (data[i] != s.data[i]) {
return false;
}
}
return true;
}
}
测试类
package Howe;
public class TestStack {
public static void main(String[] args) {
Stack stack = new Stack();
System.out.println(stack.isEmpty());
stack.push("王");//添加
stack.push("帅");//添加
stack.push("哥");//添加
System.out.println(stack);
System.out.println("现有元素为:"+stack.size());//现有元素
System.out.println(stack.isEmpty());//看是否存满
System.out.println("栈顶元素为:"+stack.peek());//查看栈顶元素
}
}
结果为:
true
[王, 帅, 哥]
现有元素为:3
false
栈顶元素为:哥
3.设计一个队列
package Howe;
public class Queue {
private Stack stackA;
private Stack stackB;
//创建默认的队列对象
public Queue(){
this.stackA = new Stack();
this.stackB = new Stack();
}
//进队一个元素
public void offer(int e){
this.stackA.push(e);
}
//出队一个元素
public int poll(){
remove();
return (int) stackB.pop();
}
private void remove() {
if (this.stackB.size() == 0){
while (this.stackA.size() != 0){
this.stackB.push(this.stackA.pop());
}
}
}
//查看队首元素
public int element(){
remove();
return (int) this.stackB.peek();
}
//获取队列中元素的个数
public int size(){
remove();
return this.stackB.size();
}
//判断队列是否为空
public boolean isEmpty(){
remove();
return this.stackB.size() == 0 && this.stackA.size() == 0;
}
//清空队列
public void clear(){
this.stackA.clear();
this.stackB.clear();
}
//返回队列的字符串形式
public String toString(){
return this.stackB.toString();
}
//对比两个队列是否相等
@Override
public boolean equals(Object o) {
Queue queue = (Queue) o;
if (this.size() != queue.size()) {
return false;
}
if (this.stackA.equals(queue.stackA) && this.stackB.equals(queue.stackB)){
return true;
}else {
return false;
}
}
}
测试:
package Howe;
public class QueueTest {
public static void main(String[] args) {
Queue queue = new Queue();
System.out.println("队列是否为空:"+queue.isEmpty());
queue.offer(1);
queue.offer(2);
queue.offer(3);
System.out.println("出队的元素为:"+queue.poll());
System.out.println("队首元素为:"+queue.element());
System.out.println("返回字符串形式为:"+queue.toString());
Queue queue1 = new Queue();
queue1.offer(456);
queue1.offer(789);
System.out.println(queue.equals(queue1));
}
}
结果为:
队列是否为空:true
出队的元素为:1
队首元素为:2
返回字符串形式为:[3, 2]
false
4.设计一个双向链表
public class LinkedList {
private Node first;
private Node last;
private int size;
public LinkedList() {
}
public void add(Object obj) {
// 向尾部添加一个新的节点
Node newNode = new Node();
newNode.value = obj;
// 判断是否是第一次添加
if (first == null) {
this.first = newNode;
this.last = newNode;
} else {
newNode.prev = last;
last.next = newNode;
last = newNode;
}
this.size++;
}
public Object get(int index) {
if (index >= this.size || index < 0) {
throw new RuntimeException("对不起,不存在这个下标");
}
Node temp = first;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
return temp.value;
}
class Node {
Node prev;
Node next;
Object value;
public Node() {
}
public Node(Node prev, Object value, Node next) {
this.prev = prev;
this.next = next;
this.value = value;
}
}
}
测试
public class TestLinkedList {
public static void main(String[] args) {
LinkedList linkedList=new LinkedList();
linkedList.add(123);
linkedList.add(456);
linkedList.add(789);
System.out.println(linkedList.get(0));
System.out.println(linkedList.get(1));
}
}
结果为:
123
456
第二天
作业:
某个人进入如下一个棋盘中,要求从左上角开始走,
最后从右下角出来(要求只能前进,不能后退),
其中,有些点标志为1,表示该点为无法通过的点,
问题:共有多少种走法?
0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0
1 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0
public class Howe {
public static void main(String[] args) {
int[][] list = {
{0, 0, 0, 0, 1, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 1, 0},
{1, 0, 0, 0, 1, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 0, 0},
};
System.out.println("共有" + theOne(list) + "种走法");
}
public static int theOne(int[][] arr) {
if (arr[0][0]==1) return 0;
int m = arr.length, n = arr[0].length;
int[][] dw = new int[m][n];
for (int i = 0; i < m && arr[i][0] == 0; i++){
dw[i][0] = 1;
}
for (int i = 0; i < n && arr[0][i] == 0; i++){
dw[0][i] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (arr[i][j] == 0){
dw[i][j] = dw[i - 1][j] + dw[i][j - 1];
}
}
}
return dw[m - 1][n - 1];
}
}
结果为:
一共有24种走法
容器入门篇:
自定义容器
Java的容器主要分为2个大类,即Collection和Map。Collection代表着集合,类似数组,只保存一个数字。而Map则是映射,保留键值对两个值。
List(对付顺序的好帮手): 存储的元素是有序的、可重复的。
Set (注重独一无二的性质):存储的元素是无序的、不可重复的。
Queue (实现排队功能的叫号机):按特定的排队规则来确定先后顺序,存储的元素是有序的、可重复的。
Map (用 key 来搜索的专家) :使用键值对(key-value)存储,类似于数学上的函数 y=f(x),“x” 代表 key,“y” 代表 value,key 是无序的、不可重复的,value 是无序的、可重复的,每个键最多映射到一个值。
java集合
集合的继承关系
|-- Collection
|-- List // 线性表
|-- Set // 哈希表
|-- Queue // 队|-- Map // 键值对,映射
注意:容器中,不能保存基本数据类型!!!
如果一定要使用基本数据类型,则需要使用它们的包装类
注意:删除基本数据类型,需要手动装箱
否则,int默认是下标,而不是数据本书
ArrayList源码解析:
1、Vector默认的容量是10;
2、Vector是线程安全的容器,操作方法都加了同步锁
3、ArrayList是非线程安全的容器
4、ArrayList根据调用不同的构造函数,初始化容器不同
如果使用无参的构造,默认容量是0,节约内存,
一旦添加元素,会发生第一次扩容,默认容量为10;
如果有参的构造,则传递为多少,默认就是多少。
ArrayList alist = new ArrayList(); // 默认容量0
ArrayList alist = new ArrayList(8); // 默认容量8
注意: 如果在开发过程中,数据大小基本确定,建议使用有参的构造函数,减少频繁扩容,提高性能当然如果不能确定的话,可以使用无参的构造。