本文主要是介绍week07_day01_自己实现LinkedList、MyStack,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
head 和 tail 是两个哨兵结点,不存储值。
MyList和MyIterator接口的代码和上节课一模一样
MyList:
package com.cskaoyan.list;/*** @author shihao* @create 2020-05-15 17:28*///想让MyArrayList和LinkedList也可以实现自己的foreach循环,
// 就得让MyList实现接口Iterable,表示有迭代的能力
public interface MyList<E> extends Iterable<E> {boolean add(E e);void add(int index, E e);void clear();boolean contains(Object obj);E get(int index);int indexOf(Object obj);boolean isEmpty();//MyIterator模仿的是listIterator//应当实现一个迭代器,对MyList进行遍历MyIterator<E> iterator();MyIterator<E> iterator(int index);int lastIndexOf(Object obj);E remove(int index);boolean remove(Object obj);E set(int index, E e);int size();
}
MyIterator:
package com.cskaoyan.list;/*** @author shihao* @create 2020-05-16 8:09*/import java.util.Iterator;//MyIterator模仿的是listIterator
//MyIterator
public interface MyIterator<E> extends Iterator<E> {boolean hasNext();boolean hasPrevious();E next();E previous();int nextIndex();int previousIndex();void add(E e);void remove();void set(E e);
}
MyLinkedList:
package com.cskaoyan.list;import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.NoSuchElementException;/*** @author shihao* @create 2020-05-16 21:16*/
public class MyLinkedList<E> implements MyList<E> {//属性//MyLinkedList底层是一个双端队列private Node head;private Node tail;private int size;private int modCount;//不需要默认容量和最大容量//Node不依赖于外部类对象而存在,所以将Node设置为static//当然,加上static后就不能将value设置为E类型,//因为泛型是创建对象的时候才把泛型参数传入进来的,泛型依赖于对象存在private static class Node {Node prev;Object value;Node next;public Node(Object value) {this.value = value;}public Node(Node prev, Object value, Node next) {this.prev = prev;this.value = value;this.next = next;}}//构造方法//创建一个空链表public MyLinkedList() {head = new Node(null);tail = new Node(head, null, null);head.next = tail;}//应当在head之前和tail之后设置哨兵结点//方法/*** 在线性表最后添加元素** @param e 待添加的元素* @return 如果添加成功返回true*/@Overridepublic boolean add(E e) {add(size, e);return true;}/*** 在线性表指定位置添加元素** @param index 指定索引位置* @param e 待添加的元素*/@Overridepublic void add(int index, E e) {checkIndexForAdd(index); //index的范围:[0,size]//需要考虑一种特殊情况:index == size时if (index == size) {Node nodeToAdd = new Node(tail.prev, e, tail);tail.prev.next = nodeToAdd;tail.prev = nodeToAdd;} else {//获取索引为index的结点Node node = getNode(index); //index的范围:[0,size-1]//在node前面插入新节点Node nodeToAdd = new Node(node.prev, e, node);node.prev.next = nodeToAdd;node.prev = nodeToAdd;}size++;modCount++;}/*** 获取index位置的结点** @param index* @return index位置的结点* <p>* A --> B --> C size=3* A --> B --> C --> D size=4*/private Node getNode(int index) {if (index * 2 < size) {Node x = head.next;//x最终指向索引为index的结点for (int i = 0; i < index; i++) {x = x.next;}return x;} else {Node x = tail.prev;//x最终指向索引为index的结点for (int i = size - 1; i > index; i++) {x = x.prev;}return x;}}private void checkIndexForAdd(int index) {if (index < 0 || index > size) {throw new IndexOutOfBoundsException("index = " + index + ", size = " + size);}}/*** 清空链表中所有元素*/@Overridepublic void clear() {head.next = tail;tail.prev = head;size = 0;modCount++;}/*** 判断线性表中是否有与指定元素相等的元素** @param obj 指定对象* @return 如果存在这样额元素返回true,否则返回false*/@Overridepublic boolean contains(Object obj) {return indexOf(obj) != -1;}/*** 获取指定索引位置的元素** @param index 指定索引位置* @return 指定索引位置的元素*/@Override@SuppressWarnings("unchecked")public E get(int index) {checkIndex(index);return (E) getNode(index).value;}private void checkIndex(int index) {if (index < 0 || index > size - 1) {throw new IndexOutOfBoundsException("index = " + index + ", size = " + size);}}/*** 获取线性表中第一个与指定对象相等的元素** @param obj 指定对象* @return 第一个和指定对象相等的元素的索引,如果不存在这样的索引返回-1*/@Overridepublic int indexOf(Object obj) {if (obj == null) {Node x = head.next;for (int i = 0; i < size; i++) {if (x.value == null) return i;x = x.next;}} else {Node x = head.next;for (int i = 0; i < size; i++) {if (obj.equals(x.value)) return i;x = x.next;}}return -1;}/*** 判断线性表是否为空** @return 为空返回true,否则返回false*/@Overridepublic boolean isEmpty() {return size == 0;}/*** 获取最后一个与指定对象相等元素的索引** @param obj 指定对象* @return 最后一个与指定对象相等元素的索引,如果不存在这样的元素返回-1*/@Overridepublic int lastIndexOf(Object obj) {if (obj == null) {Node x = tail.prev;for (int i = size - 1; i >= 0; i--) {if (x.value == null) return i;x = x.prev;}} else {Node x = tail.prev;for (int i = size - 1; i >= 0; i--) {if (obj.equals(x.value)) return i;x = x.prev;}}return -1;}/*** 删除指定索引位置的元素,并把被删除的元素返回** @param index 索引* @return 被删除的元素*/@Override@SuppressWarnings("unchecked")public E remove(int index) {checkIndex(index);Node node = getNode(index);node.prev.next = node.next;node.next.prev = node.prev;size--;modCount++;return (E) node.value;}@Overridepublic boolean remove(Object obj) {//不要用以下写法,因为indexOf会遍历一遍链表,remove(index)也会//遍历一遍链表,其实整个方法只需遍历一次链表即可,我们却遍历了两次
/* int index = indexOf(obj);if (index == -1) return false;remove(index);return true;*///只遍历一次if (obj == null) {Node x = head.next;for (int i = 0; i < size; i++) {if (x.value == null) {//删除x结点x.prev.next = x.next;x.next.prev = x.prev;size--;modCount++;return true;}x = x.next;}} else {Node x = head.next;for (int i = 0; i < size; i++) {if (obj.equals(x.value)) {//删除x结点x.prev.next = x.next;x.next.prev = x.prev;size--;modCount++;return true;}x = x.next;}}return false;}/*** 将索引位置元素替换为新值** @param index 索引* @param e 新值* @return 旧值*/@Overridepublic E set(int index, E e) {checkIndex(index);Node node = getNode(index);E retValue = (E) node.value;node.value = e;return retValue;}/*** 获取线性表中元素的个数** @return 元素的个数*/@Overridepublic int size() {return size;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder("[");Node x = head.next;while (x != tail) {sb.append(x.value).append("-->");x = x.next;}if (size != 0) {sb.delete(sb.length() - 3, sb.length());}return sb.append("]").toString();}/*** 获取迭代器,光标后面的元素的索引为0** @return 迭代器*/@Overridepublic MyIterator<E> iterator() {return new Itr();}/*** 获取迭代器,光标后面的元素的索引为index** @param index 光标后面的元素的索引* @return 迭代器*/@Overridepublic MyIterator<E> iterator(int index) {checkIndexForAdd(index);return new Itr(index);}private class Itr implements MyIterator<E> {//属性int cursor; //光标后面元素的索引Node node; //光标后面的结点int expModCount = modCount; //期待被修改的次数//lastRet表示上一次返回的结点Node lastRet = null; //null表示最近没有返回结点或最近返回的结点已失效//构造方法//无需加public,因为外界不可能通过构造方法访问到Itr内部类Itr() {node = head.next;}Itr(int index) {cursor = index;if (index == size) {node = tail;} else {node = getNode(index);}}//方法/*** 判断光标后面是否还有元素** @return 如果有元素返回true,没有元素返回false*/@Overridepublic boolean hasNext() {return cursor != size;}/*** 判断光标前面是否还有元素** @return 如果有元素返回true,没有元素返回false*/@Overridepublic boolean hasPrevious() {return cursor != 0;}/*** 将光标往后移动一个元素,并把被光标越过的元素返回** @return 被光标越过的元素*/@Override@SuppressWarnings("unchecked")public E next() {checkConModException();if (!hasNext()) {throw new NoSuchElementException();}cursor++;lastRet = node;node = node.next;return (E) lastRet.value;}private void checkConModException() {if (expModCount != modCount) {throw new ConcurrentModificationException();}}/*** 将光标往前移动一个位置,并把被光标越过的元素返回** @return 被光标越过的元素*/@Override@SuppressWarnings("unchecked")public E previous() {checkConModException();if (!hasPrevious()) {throw new NoSuchElementException();}cursor--;node = node.prev;lastRet = node;return (E) lastRet.value;}/*** 获取光标后面元素的索引** @return*/@Overridepublic int nextIndex() {return cursor;}/*** 获取光标前面元素的索引** @return*/@Overridepublic int previousIndex() {return cursor - 1;}/*** 在光标后面添加元素** @param e 待添加的元素*/@Overridepublic void add(E e) {//不用这句代码,add(cursor,e)的时间复杂度为O(n)//MyLinkedList.this.add(cursor,e);//完全可以在O(1)的时间复杂度下完成add操作Node nodeToAdd = new Node(node.prev, e, node);node.prev.next = nodeToAdd;node.prev = nodeToAdd;size++;cursor++;lastRet = null; //添加完元素后让最近返回的元素失效//如果没有这句代码,本迭代器修改之后,其他迭代器是感知不到修改的//也就是说理应报并发修改异常但却没报//解释:expModCount = ++modCount;后,本迭代器的expModCount和外部类中的modCount值相同//而在本迭代器创立之前的其他迭代器的expModCount可是比现在的++modCount小1,既然不相等//在执行it.next()时,调用 checkConModException();就会报并发修改异常expModCount = ++modCount;}/*** 删除最近返回的元素*/@Overridepublic void remove() {checkConModException();//当最近返回的元素失效或者最近没有返回的元素时if (lastRet == null) {throw new IllegalStateException();}//删除nodelastRet.prev.next = lastRet.next;lastRet.next.prev = lastRet.prev;//4个属性值的变化expModCount = ++modCount;size--;//如果是逆向遍历,node和lastRet是相等的if (lastRet == node) {node = node.next;} else { //如果是正向遍历,node和lastRet是不相等的cursor--;}lastRet = null;}/*** 替换最近返回的元素** @param e 替换后的值*/@Overridepublic void set(E e) {checkConModException();if (lastRet == null) {throw new IllegalStateException();}lastRet.value = e;lastRet = null;}}public static void main(String[] args) {MyLinkedList<String> list = new MyLinkedList<>();System.out.println(list);list.add("hello");list.add("world");list.add("java");System.out.println(list);// void add(int index, E e)// list.add(0, "A");// list.add(1, "A");// list.add(list.size(), "A");// list.add(list.size() + 1, "A");// list.add(-1, "A");// System.out.println(list);// void clear(), int size(), boolean isEmpty()/*System.out.println(list);System.out.println(list.size());System.out.println(list.isEmpty());list.clear();System.out.println(list);System.out.println(list.size());System.out.println(list.isEmpty());*/// boolean contains(Object obj)/*System.out.println(list.contains("java")); //trueSystem.out.println(list.contains("wuhan")); //falseSystem.out.println(list.contains(null));//falselist.add(null);System.out.println(list.contains(null));//true*/// int indexOf(Object obj)
/* list.add("hello");System.out.println(list);System.out.println(list.indexOf("hello"));System.out.println(list.indexOf(null));list.add(0, null);list.add(null);System.out.println(list);System.out.println(list.indexOf(null));*/// int lastIndexOf(Object obj)
/* list.add("hello");System.out.println(list);System.out.println(list.lastIndexOf("hello"));System.out.println(list.lastIndexOf(null));list.add(0, null);list.add(null);System.out.println(list);System.out.println(list.lastIndexOf(null));*/// E get(int index)// System.out.println(list.get(1));// System.out.println(list.get(-1));// System.out.println(list.get(list.size()));// E remove(index)// System.out.println(list.remove(1));// System.out.println(list.remove(-1));// System.out.println(list.remove(list.size()));// System.out.println(list);// boolean remove(Object)/*list.add("hello");System.out.println(list.remove("hello"));System.out.println(list);System.out.println(list.remove(null));System.out.println(list);list.add(0, null);list.add(null);System.out.println(list);System.out.println(list.remove(null));System.out.println(list);*/// E set(int index, E e)// System.out.println(list.set(2, "JAVA"));// System.out.println(list.set(-1, "JAVA"));// System.out.println(list.set(list.size(), "JAVA"));// System.out.println(list);/****************************************************** Iterator*****************************************************/
// MyLinkedList<String> list = new MyLinkedList<>();
// list.add("hello");
// list.add("world");
// list.add("java");// boolean hasPrevious(), boolean hasNext()// MyIterator<String> it = list.iterator();// MyIterator<String> it = list.iterator(list.size());// MyIterator<String> it = list.iterator(1);// System.out.println(it.hasPrevious());// System.out.println(it.hasNext());// E previous(), E next()/*MyIterator<String> it = list.iterator();System.out.println(it.next());System.out.println(it.next());System.out.println(it.next());System.out.println(it.next());*//* MyIterator<String> it = list.iterator(list.size());System.out.println(it.previous());System.out.println(it.previous());System.out.println(it.previous());System.out.println(it.previous());*/// int previousIndex() int nextIndex()/*MyIterator<String> it = list.iterator();System.out.println(it.previousIndex());System.out.println(it.nextIndex());it.next();System.out.println(it.previousIndex());System.out.println(it.nextIndex());it.next();System.out.println(it.previousIndex());System.out.println(it.nextIndex());it.next();System.out.println(it.previousIndex());System.out.println(it.nextIndex());*/// void add(E e)/*MyIterator<String> it = list.iterator(1);it.add("A");it.add("B");it.add("C");System.out.println(list);System.out.println(it.next());*/// 在"hello"后面添加元素//测试两个迭代器的增加和遍历操作
// MyIterator<String> iterator = list.iterator();
// for (MyIterator<String> it = list.iterator(); it.hasNext(); ) {
// String s = it.next();
// if ("hello".equals(s)) {
// int index = it.nextIndex();
// it.add("A");
// }
// }
// System.out.println(list);
// //演示Itr中的add方法中的 expModCount = ++modCount; 这句代码的作用
// while (iterator.hasNext()) {
// String s = iterator.next();
// System.out.println(s);
// }// void remove()/*MyIterator<String> it = list.iterator();// it.remove();it.next();it.remove();System.out.println(list);*/
/* MyIterator<String> it = list.iterator(list.size());it.previous();//it.add("HELLO");//add一次后lastRet所代表的最近返回的元素就失效了it.remove();System.out.println(list);//remove一次后lastRet所代表的最近返回的元素就失效了//it.remove();*/// 删除"hello"/*for(MyIterator<String> it = list.iterator(); it.hasNext(); ) {String s = it.next();if ("hello".equals(s)) {int index = it.previousIndex();list.remove(index);}}System.out.println(list);*//* MyIterator<String> it = list.iterator();// it.set("HELLO");it.next();it.set("HELLO");// it.set("HeLLo");System.out.println(list);*//*MyIterator<String> it = list.iterator(list.size());it.previous();it.set("JAVA");System.out.println(list);*/}}
栈的非顺序映象(链栈):
····················································································································································································································
栈的API:
入栈 (push):在栈顶添加元素,O(1)
出栈 (pop):从栈顶删除元素,O(1)
查看栈顶元素 (peek):访问栈顶元素但不弹出,O(1)
判空 (isEmpty):判断栈是否为空, 方便遍历,O(1)
栈的非顺序映象(链栈):
package com.cskaoyan.stack;import java.util.EmptyStackException;/*** @author shihao* @create 2020-05-18 22:37* <p>* 栈的非顺序映象* API:* void push(E e)* E pop()* E peek()* boolean isEmpty()*/
public class MyStack<E> {//使用单链表作为底层的数据结构private static class Node {Object value;Node next;public Node(Object value) {this.value = value;}public Node(Object value, Node next) {this.value = value;this.next = next;}}//属性private Node top;//构造方法//默认会实现无参构造方法,top会置为null//方法/*** 入栈,即在栈顶添加元素** @param e 待添加的元素*/public void push(E e) {top = new Node(e, top);}/*** 出栈,即删除栈顶元素* @return 删除掉的元素*/@SuppressWarnings("unchecked")public E pop(){if (this.isEmpty()){throw new EmptyStackException();}E removeValue = (E) top.value;top = top.next;return removeValue;}/*** 查看栈顶元素* @return 栈顶元素*/@SuppressWarnings("unchecked")public E peek(){if(this.isEmpty()){throw new EmptyStackException();}return (E) top.value;}/*** 判断栈是否为空** @return 栈空返回true,否则返回false*/public boolean isEmpty() {return top == null;}}
栈的顺序映象(顺序栈):
package com.cskaoyan.stack;import java.util.EmptyStackException;/*** @author shihao* @create 2020-05-19 7:26* <p>* 栈的顺序映象* API:* void push(E e)* E pop()* E peek()* boolean isEmpty()*/
public class MyStack02<E> {//栈的默认容量private static final int DEFAULT_CAPACITY = 10;//栈的最大容量private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8;//属性private Object[] elements;private int top = -1;//构造方法public MyStack02() {elements = new Object[DEFAULT_CAPACITY];}public MyStack02(int capacity) {if (capacity <= 0 || capacity > MAX_CAPACITY) {throw new IllegalArgumentException("capacity = " + capacity);}elements = new Object[capacity];}//方法/*** 入栈,即在栈顶添加元素** @param e 待添加的元素*/public void push(E e) {if (top == (elements.length - 1)) {//扩容int newLength = calculateCapacity();grow(newLength);}top++;elements[top] = e;}private void grow(int newCapacity) {//数组大小是不可变的,应当新建一个更大的数组,将原数组的元素传递给它Object[] newArr = new Object[newCapacity];for (int i = 0; i < elements.length; i++) {newArr[i] = elements[i];}//elements指向新数组elements = newArr;}private int calculateCapacity() {if (elements.length == MAX_CAPACITY) {throw new RuntimeException("Stack is too large!");}int newCapacity = elements.length + elements.length >> 1;if (newCapacity > MAX_CAPACITY || newCapacity < 0) {newCapacity = MAX_CAPACITY;}return newCapacity;}/*** 出栈,即删除栈顶元素** @return 删除掉的元素*/@SuppressWarnings("unchecked")public E pop() {if (top == -1) {throw new EmptyStackException();}E retValue = (E) elements[top];elements[top] = null;top--;return retValue;}/*** 查看栈顶元素** @return 栈顶元素*/@SuppressWarnings("unchecked")public E peek() {if (top == -1) {throw new EmptyStackException();}return (E) elements[top];}/*** 判断栈是否为空** @return 栈空返回true,否则返回false*/public boolean isEmpty() {return top == -1;}}
练习题:反转字符串(要求用栈实现)
输入:“ABC”
输出:“CBA”
思路:
a.遍历字符串,获取每一个字符。charAt(int index)
b.将字符入栈
c.依次将字符出栈,并拼接
public class Demo01 {public static void main(String[] args) {String s = "123456";System.out.println(reverse(s));}private static String reverse(String original) {MyStack02<Character> myStack = new MyStack02<>();for (int i = 0; i < original.length(); i++) {char c = original.charAt(i);myStack.push(c);}StringBuilder sb = new StringBuilder();while (!myStack.isEmpty()) {sb.append(myStack.pop());}return sb.toString();}
}
应用场景:
-
函数调用栈:如在主方法中调用一个fun方法,会为fun方法创建一个栈帧,而一定是fun方法先执行结束的,然后主方法再执行结束。先调用的方法(主方法)后执行完,后调用的方法(fun方法)先执行完。这正好满足FILO特性。
-
括号匹配问题
老师代码:
public class StackDemo2 {public static void main(String[] args) {// String original = "([{}])";// String original = "()[]{";String original = "public static void main(String[ args) {System.out.println(bracketMatched(original));}";System.out.println(bracketMatched(original));}/*时间复杂度:O(n)空间复杂度:O(a):字符串中括号的个数*/public static boolean bracketMatched(String original) {Deque<Character> stack = new LinkedList<>();// 遍历字符串, 获取每一个字符for (int i = 0; i < original.length(); i++) {char c = original.charAt(i);if (c == '(') stack.push(')');if (c == '[') stack.push(']');if (c == '{') stack.push('}');if (c == ')' || c == ']' || c== '}') {if (stack.isEmpty()) return false;if (c != stack.pop()) return false;}}// 遍历结束后return stack.isEmpty();}
}
我的代码(天勤、LeetCode之有效的括号):
class Solution {public boolean isValid(String s) {char[] stack=new char[s.length()];int top=-1;for(int i=0;i<s.length();i++){char ch=s.charAt(i);if(ch=='('||ch=='['||ch=='{')stack[++top]=ch;else{if(top==-1)return false; //缺左括号char left=stack[top--];if(!isMathced(left,ch))return false; //左右括号不匹配}}if(top!=-1)return false; //缺右括号return true;}private boolean isMathced(char left,char right){if(left=='('&&right==')')return true;else if(left=='['&&right==']')return true;else if(left=='{'&&right=='}')return true;elsereturn false;}
}
-
编译器利用栈实现表达式求值
具体代码看之前天勤笔记。 -
浏览器的前进后退功能
-
利用栈实现 DFS
这篇关于week07_day01_自己实现LinkedList、MyStack的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!