知识点
背包:只进不出,迭代顺序不确定(即无先后顺序)
队列:先进先出
栈 :后进先出
两种基础数据结构:数组和链表
数据结构 | 优点 | 缺点 |
数组 | 通过索引可以访问任意元素 | 在初始化时就需要知道元素的数量 |
链表 | 使用的空间大小和元素数量成正比 | 需要通过引用访问任意元素 |
练习
1.3.1 为FixedCapacityStackOfStrings添加一个方法isFull(). /*其中注意N的含义,别和数组下标完全混淆*/
public class FixedCapacityStackOfStrings { private String[] a; private int N; public FixedCapacityStackOfStrings(int cap) { a=new String[cap]; } public boolean isEmpty() { return N==0; } public boolean isFull() //检查是否已满 { return N==a.length; } public int size() { return N; } public void push(String item) { a[N++]=item; } public String pop() { return a[--N]; } public static void main(String[] args) throws IOException { FixedCapacityStackOfStrings s=new FixedCapacityStackOfStrings(3); while(!s.isFull()) s.push("first"); while(!s.isEmpty()) StdOut.println(s.pop()); } }
1.3.3 假设某个用例程序会进行一系列入栈和出栈的混合操作.入栈操作会将整数0到9按顺序压入栈;出栈操作会打印出返回值.下面哪种序列是不可能产生的.
(a) 4 3 2 1 0 9 8 7 6 5 (b) 4 6 8 7 5 3 2 9 0 1 (c) 2 5 6 7 4 8 9 3 1 0 (d) 4 3 2 1 0 5 6 7 8 9 (e) 1 2 3 4 5 6 9 8 7 0 (f) 0 4 6 5 3 8 1 7 2 9 (g) 1 4 7 9 8 6 5 3 0 2 (h) 2 1 4 3 6 5 8 7 9 0
其中 b---(0,1出错) f---(1,7,2出错) g---(0,2出错)
/*是否可以构造一个函数来进行判断?---找出其中遵守的规律?*/
1.3.4 编写一个Stack的用例Parentheses,从标准输入中读取一个文本流并使用栈判定其中的括号是否配对完整.例如[()]{}{[()]}为true,对于[(])程序则打印false.
个人编写的版本(较麻烦,且需要文本中括号要用空格分隔)
public class H1_3_04 { public static void main(String[] args) { In in=new In(); @SuppressWarnings("deprecation") String[] arr=In.readStrings("h1_3_4.txt"); //注:其中文本中用空格分隔每个字符串,如[ ( ) ] for(String s:arr) StdOut.printf("%s",s); StdOut.println(check(arr)); in.close(); } public static boolean check(String[] arr) //循环判断每个字符串 { Stack<String> stack=new Stack<String>(); for(int i=0;i<arr.length;i++) { if(check(arr[i],stack)==false) return false; } return true; } public static boolean check(String a,Stack<String> stack) //判断每个右括号是否有匹配的左括号 { switch (a) { case "]": while(true) { if(stack.isEmpty()) return false; if(stack.pop().equals("[")) return true; } case ")": while(true) { if(stack.isEmpty()) return false; if(stack.pop().equals("(")) return true; } case "}": while(true) { if(stack.isEmpty()) return false; if(stack.pop().equals("{")) return true; } default: stack.push(a); return true; } } }
习题解答给出的答案: /*巧用了字符串的charAt方法,无需将每个字符分离出来*/
public class Parentheses { private static final char LEFT_PAREN = ‘(‘; //paren---括弧 private static final char RIGHT_PAREN = ‘)‘; private static final char LEFT_BRACE = ‘{‘; //brace---大括号 private static final char RIGHT_BRACE = ‘}‘; private static final char LEFT_BRACKET = ‘[‘; //bracket---括号 private static final char RIGHT_BRACKET = ‘]‘; public static boolean isBalanced(String s) { Stack<Character> stack = new Stack<Character>(); for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == LEFT_PAREN) stack.push(LEFT_PAREN); if (s.charAt(i) == LEFT_BRACE) stack.push(LEFT_BRACE); if (s.charAt(i) == LEFT_BRACKET) stack.push(LEFT_BRACKET); if (s.charAt(i) == RIGHT_PAREN) { if (stack.isEmpty()) return false; if (stack.pop() != LEFT_PAREN) return false; } else if (s.charAt(i) == RIGHT_BRACE) { if (stack.isEmpty()) return false; if (stack.pop() != LEFT_BRACE) return false; } else if (s.charAt(i) == RIGHT_BRACKET) { if (stack.isEmpty()) return false; if (stack.pop() != LEFT_BRACKET) return false; } } return stack.isEmpty(); } public static void main(String[] args) { In in = new In(); String s = in.readAll().trim(); StdOut.println(isBalanced(s)); } }
1.3.6 下面这段代码对队列q进行了什么操作 /*主旨在于理解队列和栈两者的模式和区别*/
Stack<String> stack=new Stack<String>(); while(!q.isEmpty()) stack.push(q.dequeue()); while(!stack.isEmpty()) q.enqueue(stack.pop());
将队列逆序
1.3.7 为Stack添加一个方法peek(),返回栈中最近添加的元素(而不弹出它). //以下为作者给出的Stack中的peek()函数
public Item peek() { if (isEmpty()) throw new NoSuchElementException("Stack underflow"); return first.item; }
1.3.9 编写一段程序,从标准输入得到一个缺少左括号的表达式并打印出补全括号之后的中序表达式. /*此题比较关键在于")"输入时的情况---重点题*/
例如: 输入 1+2)*3-4)*5-6))) 输出 ((1+2)*((3-4)*(5-6)))
public class H1_3_09 { public static void main(String[] args) { In in=new In(); @SuppressWarnings("deprecation") String[] arr=In.readStrings("h1_3_09.txt"); for(int i=0;i<arr.length;i++) StdOut.printf("%s",arr[i]); StdOut.println(); StdOut.println(fillParen(arr)); in.close(); } public static String fillParen(String[] arr) //补上左括号操作 { Stack<String> operator=new Stack<String>(); Stack<String> value=new Stack<String>(); for(int i=0;i<arr.length;i++) { if(arr[i].equals("(")); //可以删去该句 else if(arr[i].equals("*")||arr[i].equals("/") ||arr[i].equals("+")||arr[i].equals("-")||arr[i].equals("sqrt")) //操作符情况 operator.push(arr[i]); else if(arr[i].equals(")")) //右括号情况---关键 { String op = operator.pop(); String v = value.pop(); if (op.equals("+") ||op.equals("-") ||op.equals("*") ||op.equals("/")) v = String.format("( %s %s %s )", value.pop(), op, v); else if (op.equals("sqrt")) v = String.format("( %s %s )", op, v); value.push(v); //记得将操作结果存回数值栈中 } else value.push(arr[i]); } return value.pop(); } }
注:其中"h1_3_09.txt"中的内容为1 + 2 ) * 3 - 4 ) * 5 - 6 ) ) ) ---即之间有空格分开
1.3.10&1.3.11 编写一个过滤器InfixToPostfix,将算术表达式由中序表达式转为后序表达式.并编写一个程序求解后序表达式的值并打印 /*中序表达式转换为后序表达式以及后序表达式的求解---重点题*/
public class H1_3_10 { public static void main(String[] args) { String str="(1+2)*3/4"; String pfstr=infixToPostfix(str); StdOut.println(pfstr); StdOut.println(evaluatePostfix(pfstr)); } //计算后序表达式的值 public static double evaluatePostfix(String str) { Stack<String> stack=new Stack<String>(); for(int i=0;i<str.length();i++) { char c=str.charAt(i); if(!isOperator(c)) stack.push(Character.toString(c)); else { double a1=Double.parseDouble(stack.pop().toString()); double a2=Double.parseDouble(stack.pop().toString()); stack.push(Double.toString(doOperator(a1,a2,c))); } } return Double.parseDouble(stack.pop()); } //根据操作符进行操作 public static double doOperator(double a1,double a2,char c) { switch(c) { case ‘+‘: return a2+a1; case ‘-‘: return a2-a1; case ‘/‘: return a2*1.0/a1; case ‘*‘: return a2*1.0*a1; default: throw new NoSuchElementException("operator is illegal!"); } } //将前序表达式转换为后序表达式 public static String infixToPostfix(String str) { Stack<Character> stack=new Stack<Character>(); String express=""; for(int i=0;i<str.length();i++) { char c=str.charAt(i); if(!isOperator(c)) //情形1:操作数情况 express+=c; else { if(c==‘(‘) //情形2:左括号情况 stack.push(c); else if(c==‘)‘) //情形3:右括号情况 { if(stack.isEmpty()) throw new NoSuchElementException("Stack underflow"); else { char temp=stack.pop(); while(temp!=‘(‘) { express+=temp; temp=stack.pop(); } } } else //情形4:+-*/情况 { if(stack.isEmpty()||priority(stack.peek())<priority(c)) stack.push(c); else { while(!stack.isEmpty()&&stack.peek()!=‘(‘&&priority(stack.peek())>=priority(c)) express+=stack.pop(); stack.push(c); } } } } if(!stack.isEmpty()) //栈中还有操作符情况 { while(!stack.isEmpty()) { if(stack.peek()==‘(‘) throw new NoSuchElementException("Illegal input"); else express+=stack.pop(); } } return express; } //判断字符是否为符号 public static boolean isOperator(char c) { if(c==‘+‘||c==‘-‘||c==‘*‘||c==‘/‘||c==‘(‘||c==‘)‘) return true; else return false; } //设定优先级 public static int priority(char c) { if(c==‘(‘) return 0; else if(c==‘*‘||c==‘/‘) return 2; else if(c==‘+‘||c==‘-‘) return 1; else return 3; } }
//关于中序转后序更加详细的内容见另一篇文章: 暂定
1.3.12 编写一个可迭代的Stack用例,它含有一个静态的copy()方法,接受一个字符串的栈作为参数并返回该栈的一个副本. 注意:这种能力是迭代器价值的一个重要体现,因为有了它我们无需改变基本API就能够实现这种功能.
???
1.3.13 假设某个用例程序会进行一系列入列和出列的混合队列操作.入列操作会将整数0到9按顺序插入队列;出列操作会打印出返回值.下面哪种序列是不可能产生的
(a) 0 1 2 3 4 5 6 7 8 9 (b) 4 6 8 7 5 3 2 9 0 1 (c) 2 5 6 7 4 8 9 3 1 0 (d) 4 3 2 1 0 5 6 7 8 9
(b)(c)(d)均是不可能产生的---根据队列的性质,只可能是(a)这一种情况
1.3.14 编写一个类ResizingArrayQueueOfStrings,使用定长数组实现队列的抽象,然后扩展实例,使用调整数组的方法突破大小的限制 /*了解队列的性质以及如何实现数组的大小调整*/
public class ResizingArrayQueueOfStrings { private String[] a; private int N=0; private int head=0; private int tail=0; public ResizingArrayQueueOfStrings(int cap) { a=new String[cap]; } public boolean isEmpty(){return N==0;} public int size(){return N;} public void resize(int max) { String[] temp = new String[max]; for (int i = 0; i < N; i++) temp[i] = a[(head + i) % a.length]; a = temp; head = 0; tail = N; } //添加元素 public void enqueue(String s) { if(N==a.length) resize(2*a.length); a[tail++]=s; if(tail==a.length) tail=0; N++; } //删除元素 public String dequeue() { if(isEmpty()) throw new NoSuchElementException("Queue underflow"); String s=a[head]; a[head]=null; head++;N--; if(head==a.length) head=0; if (N > 0 && N == a.length/4) resize(a.length/2); return s; } public static void main(String[] args) { ResizingArrayQueueOfStrings queue=new ResizingArrayQueueOfStrings(3); for(int i=0;i<7;i++) queue.enqueue(Integer.toString(i)); for(int i=0;i<5;i++) StdOut.printf("%s ",queue.dequeue()); } }
作者给出的包中的实现:
public class ResizingArrayQueue<Item> implements Iterable<Item> { private Item[] q; // queue elements private int N = 0; // number of elements on queue private int first = 0; // index of first element of queue private int last = 0; // index of next available slot /** * Initializes an empty queue. */ public ResizingArrayQueue() { // cast needed since no generic array creation in Java q = (Item[]) new Object[2]; } /** * Is this queue empty? * @return true if this queue is empty; false otherwise */ public boolean isEmpty() { return N == 0; } /** * Returns the number of items in this queue. * @return the number of items in this queue */ public int size() { return N; } // resize the underlying array private void resize(int max) { assert max >= N; Item[] temp = (Item[]) new Object[max]; for (int i = 0; i < N; i++) { temp[i] = q[(first + i) % q.length]; } q = temp; first = 0; last = N; } /** * Adds the item to this queue. * @param item the item to add */ public void enqueue(Item item) { // double size of array if necessary and recopy to front of array if (N == q.length) resize(2*q.length); // double size of array if necessary q[last++] = item; // add item if (last == q.length) last = 0; // wrap-around N++; } /** * Removes and returns the item on this queue that was least recently added. * @return the item on this queue that was least recently added * @throws java.util.NoSuchElementException if this queue is empty */ public Item dequeue() { if (isEmpty()) throw new NoSuchElementException("Queue underflow"); Item item = q[first]; q[first] = null; // to avoid loitering N--; first++; if (first == q.length) first = 0; // wrap-around // shrink size of array if necessary if (N > 0 && N == q.length/4) resize(q.length/2); return item; } /** * Returns the item least recently added to this queue. * @return the item least recently added to this queue * @throws java.util.NoSuchElementException if this queue is empty */ public Item peek() { if (isEmpty()) throw new NoSuchElementException("Queue underflow"); return q[first]; } /** * Returns an iterator that iterates over the items in this queue in FIFO order. * @return an iterator that iterates over the items in this queue in FIFO order */ public Iterator<Item> iterator() { return new ArrayIterator(); } // an iterator, doesn‘t implement remove() since it‘s optional private class ArrayIterator implements Iterator<Item> { private int i = 0; public boolean hasNext() { return i < N; } public void remove() { throw new UnsupportedOperationException(); } public Item next() { if (!hasNext()) throw new NoSuchElementException(); Item item = q[(i + first) % q.length]; i++; return item; } } /** * Unit tests the <tt>ResizingArrayQueue</tt> data type. */ public static void main(String[] args) { ResizingArrayQueue<String> q = new ResizingArrayQueue<String>(); while (!StdIn.isEmpty()) { String item = StdIn.readString(); if (!item.equals("-")) q.enqueue(item); else if (!q.isEmpty()) StdOut.print(q.dequeue() + " "); } StdOut.println("(" + q.size() + " left on queue)"); } }
1.3.15 编写一个Queue用例,接受一个命令行参数k并打印出标准输入中的倒数第k个字符串(假设标准输入中至少有k个字符串) /*意图是什么呢?*/
public class H1_3_15 { public static void main(String[] args) { Queue<String> queue=new Queue<String>(); for(int i=0;i<10;i++) queue.enqueue(Integer.toString(i)); StdOut.println(Reversek(1, queue)); } public static String Reversek(int k,Queue<String> queue) { if(k>queue.size()) throw new NoSuchElementException("k is over the size"); int cnt=queue.size()-k; for(int i=0;i<cnt;i++) queue.dequeue(); return queue.dequeue(); } }
1.3.16 使用1.3.1.5节中的readInts()作为模板为Date编写一个静态方法readDates(),从标准输入中读取由练习1.2.19的表格所指定的格式的多个日期并返回一个他们的数组.
/*体现了模板的重要性,同时也体现很多问题的类似性,要举一反三*/
public class H1_3_16 { public static Date[] readDates(String name) //仿照readInts() { In in=new In(name); Queue<Date> q=new Queue<Date>(); while(!in.isEmpty()) q.enqueue(new Date(in.readString())); //由于日期形式为 5/22/1939 所以用readString int N=q.size(); Date[] a=new Date[N]; for(int i=0;i<N;i++) a[i]=q.dequeue(); return a; } public static void main(String[] args) { Date[] date=readDates("h1_3_16.txt"); for(int i=0;i<date.length;i++) StdOut.println(date[i].toString()); } }
1.3.17 为Transaction类完成练习1.3.16
public class H1_3_17 { public static Transaction[] readTransactions(String name) //仿照readInts() { In in=new In(name); Queue<Transaction> q=new Queue<Transaction>(); while(!in.isEmpty()) { //由于Transaction的格式为 Turning 5/22/1939 11.99 的格式,因此采用readLine() String[] str=in.readLine().split("\\s+"); Transaction tran=new Transaction(str[0],new Date(str[1]),Double.parseDouble(str[2])); q.enqueue(tran); } int N=q.size(); Transaction[] a=new Transaction[N]; for(int i=0;i<N;i++) a[i]=q.dequeue(); return a; } public static void main(String[] args) { Transaction[] Transaction=readTransactions("h1_3_17.txt"); for(int i=0;i<Transaction.length;i++) StdOut.println(Transaction[i].toString()); } }
链表练习
1.3.18~1.3.30(除1.3.29外) 实现一个单向链表Linked,以下的API给出具体实现的函数及其功能 /*通过该题,发现当需求一个功能再补充时思路更清晰(而不是一上来就想实现全部的)*/
函数 | 能力 | 函数 | 功能 |
int length() | 返回链表的长度 | String toString() | 显示链表 |
Node createNode(Item item) | 创造结点 | String toString(Node node) | 显示从结点开始的链表 |
add(Item item) | 在链表尾部添加结点 | Item delete() | 删除尾结点 |
void delete(Item key) | 删除链表中结点值为item的项 | Item delete(int k) | 删除链表的第k个元素 |
boolean find(Item key) | 查找是否存在元素key | Node getKthNode(int k) | 获得链表第k个结点 |
int isInLiked(Node node) | 查找某个结点是否在链表中,若在返回位置 | removeAfter(Node node) | 删除指定结点的后续结点 |
insertAfter(Node one,Node two) | 将two插入到one后面 | Item max(Node node) | 查找最大的结点值 |
Node reverse(Node x) | 将链表转为逆序 |
public class Linked<Item extends Comparable<Item>> //单链表模式 { private Node first; private int N; private class Node { Item item; Node next; public Node(Item item) { this.item=item; } } //返回链表的长度 public int length() { return N; } //显示链表 public String toString() { Node temp=first; String s=""; while(temp!=null) { s+=temp.item.toString()+" "; temp=temp.next; } return s; } //根据结点显示链表 public String toString(Node node) { Node temp=node; String s=""; while(temp!=null) { s+=temp.item.toString()+" "; temp=temp.next; } return s; } //获得独立结点---为了创造结点 public Node createNode(Item item) { return new Node(item); } //在尾部添加结点 public void add(Item item) { Node node=new Node(item); if(first==null) first=node; else { Node temp=first; while(temp.next!=null) temp=temp.next; temp.next=node; } N++; } //删除尾结点 public Item delete() { if(first==null) throw new NoSuchElementException("Over underflow!"); Node temp=first; while(temp.next!=null) temp=temp.next; Item item=temp.item; temp=null;N--; return item; } //删除链表的第k个元素 public Item delete(int k) { if(k>N||k<1) throw new NoSuchElementException("k is over the total number"); Node temp=first; Item item; if(k==1) { item=first.item; first=first.next; } else { for(int i=0;i<k-2;i++) temp=temp.next; item=temp.next.item; temp.next=temp.next.next; } N--; return item; } //删除链表中结点iten为key的项 public void delete(Item key) { while(first.item.equals(key)) { first=first.next; N--; } Node temp=first; while(temp!=null) { if(temp.next!=null&&temp.next.item.equals(key)) { temp.next=temp.next.next; N--; } else temp=temp.next; } } //查找是否存在元素key public boolean find(Item key) { Node temp=first; for(int i=0;i<N-1;i++) { if(temp.item.equals(key)) return true; else temp=temp.next; } return false; } //返回第k个链表结点---从1开始 public Node getKthNode(int k) { if(k>N) throw new NoSuchElementException("overflow!"); Node temp=first; for(int i=0;i<k-1;i++) temp=temp.next; return temp; } //判断某个结点是否存在于该链表中---返回在链表中的位置 public int isInLiked(Node node) { Node temp=first; for(int i=1;i<N;i++) { if(temp==node) return i; temp=temp.next; } return -1; } //删除该结点的后续结点 public void removeAfter(Node node) { int k=isInLiked(node); if(k==-1||k==N) return; delete(k+1); } //将第二个结点插入链表并使之成为第一个结点的后续结点 public void insertAfter(Node one,Node two) { int k=isInLiked(one); if(k==-1||two==null) return; two.next=one.next; one.next=two; N++; } //返回链表中最大的节点的值 public Item max(Node node) { if(isInLiked(node)==-1) throw new NoSuchElementException("this node is no in this link"); Item max=node.item; Node temp=node; while(temp!=null) { if(max.compareTo(temp.item)<0) max=temp.item; temp=temp.next; } return max; } //将整个链表逆序 public Node reverse(Node x) { Node first=x; Node reverse=null; while(first!=null) { Node second=first.next; first.next=reverse; reverse=first; first=second; } return reverse; } public Node reverse2(Node first) { if(first==null) return null; if(first.next==null) return first; Node second=first.next; Node rest=reverse(second); second.next=first; first.next=null; return rest; } //以下一个不好的地方,无法建立Node对象---可以将Node设置为外部类 public static void main(String[] args) { Linked<String> link=new Linked<String>(); for(int i=0;i<10;i++) link.add(Integer.toString(i)); StdOut.println(link.toString()); link.removeAfter(link.getKthNode(2)); link.insertAfter(link.getKthNode(2), link.createNode("10")); link.insertAfter(link.getKthNode(2), link.createNode("10")); link.insertAfter(link.getKthNode(2), link.createNode("10")); StdOut.println(link.toString()); link.delete("10"); StdOut.println(link.toString()); StdOut.println(link.toString(link.reverse(link.getKthNode(1)))); } }
1.3.29 用环形链表实现Queue.环形链表也是一条链表,只是没有任何结点的链接为空,且只要链表非空则last.next的值为first.
public class CircleQueue<Item> implements Iterable<Item> { private Node first; private Node last; private int N; private class Node { Item item; Node next; } public boolean isEmpty() { return N==0; } public int size() { return N; } //进队列 public void enqueue(Item item) { Node oldlast=last; last=new Node(); last.item=item; last.next=first; if(isEmpty()) first=last; else oldlast.next=last; N++; } //出队列 public Item dequeue() { if(isEmpty()) throw new NoSuchElementException("the queue is null"); Item item=first.item; first=first.next; last.next=first; N--; return item; } @Override public Iterator<Item> iterator() { return new ListIterator(); } //迭代器 private class ListIterator implements Iterator<Item> { private int i; private Node current=first; public boolean hasNext() { return i<N; } public void remove(){} public Item next() { Item item=current.item; current=current.next; i++; return item; } } public static void main(String[] args) { CircleQueue<Integer> queue=new CircleQueue<Integer>(); for(int i=0;i<10;i++) queue.enqueue(i); Iterator<Integer> itr=queue.iterator(); while(itr.hasNext()) StdOut.printf("%d ",itr.next()); StdOut.println(); queue.dequeue(); Iterator<Integer> itr2=queue.iterator(); while(itr2.hasNext()) StdOut.printf("%d ",itr2.next()); } }
1.3.31 一个嵌套类DoubleNode来构造双向链表,其中每个结点都含有一个指向前驱元素的引用和一项指向后续元素的引用.实现以下若干功能: /*对双向链表和单向链表进行对比分析*/
函数 | 功能 | 函数 | 功能 |
表头插入结点 | 表尾插入结点 | ||
表头删除结点 | 表尾删除结点 | ||
在指定结点之前插入新结点 | 在指定结点之后插入新结点 | ||
删除指定结点 |
public class DoubleLinked<Item> { private DoubleNode head; private DoubleNode tail; private int N; private class DoubleNode { Item item; DoubleNode previous; DoubleNode next; public DoubleNode(Item item) { this.item=item; } } //返回链表元素数 public int size() { return N; } //输出链表形式 public String toString() { DoubleNode temp=head; String s=""; while(temp!=null) { s+=temp.item.toString()+" "; temp=temp.next; } return s; } //向表头插入结点 public void insertHead(Item item) { DoubleNode node=new DoubleNode(item); if(head==null) head=tail=node; else { node.next=head; head.previous=node; head=node; } N++; } //向表尾插入元素 public void insertTail(Item item) { DoubleNode node=new DoubleNode(item); if(tail==null) tail=node; else { node.previous=tail; tail.next=node; tail=node; } N++; } //从表头删除结点 public Item deleteHead() { if(head==null) throw new NoSuchElementException("overflow!!"); Item item=head.item; if(head.next==null) { head=null;tail=null; N--; } else { head.next.previous=null; head=head.next; N--; } return item; } //从表尾删除结点 public Item deleteTail() { if(tail==null) throw new NoSuchElementException("overflow!!"); Item item=tail.item; if(tail.previous==null) { head=null;tail=null; N--; } else { tail.previous.next=null; tail=tail.previous; N--; } return item; } //在指定结点之后插入新结点 public void insertAfter(DoubleNode dl,DoubleNode dl2) { if(InDlist(dl)==-1) throw new NoSuchElementException("the node is not exist in link"); if(dl.next==null) { dl2.previous=dl; dl.next=dl2; N++; } else { dl2.next=dl.next; dl2.previous=dl; dl.next.previous=dl2; dl.next=dl2; N++; } } //在指定结点之前插入新结点 public void insertBefore(DoubleNode dl,DoubleNode dl2) { if(InDlist(dl)==-1) throw new NoSuchElementException("the node is not exist in link"); if(dl.previous==null) { dl2.next=dl; dl.previous=dl2; N++; } else { dl2.previous=dl.previous; dl2.next=dl; dl.previous.next=dl2; dl.previous=dl2; N++; } } //删除指定结点 public void deleteNode(DoubleNode node) { if(InDlist(node)==-1) return; if(node.next==null) { node.previous.next=null; tail=node.previous; } else if(node.previous==null) { node.next.previous=null; head=node.next; } else { node.previous.next=node.next; node.next.previous=node.previous; } N--; } //判断结点是否为链表中 public int InDlist(DoubleNode node) { DoubleNode temp=head; for(int i=1;i<=N;i++) { if(temp==node) return i; temp=temp.next; } return -1; } //返回某个结点 public DoubleNode findKthNode(int k) { if(k>N) throw new NoSuchElementException("k is over the link‘s length"); DoubleNode temp=head; for(int i=0;i<k-1;i++) temp=temp.next; return temp; } //创造一个与链表无关的结点 public DoubleNode createNode(Item item) { return new DoubleNode(item); } public static void main(String[] args) { DoubleLinked<Integer> dl=new DoubleLinked<Integer>(); for(int i=0;i<10;i++) dl.insertHead(i); StdOut.println(dl.toString()); dl.insertBefore(dl.findKthNode(2),dl.createNode(5)); StdOut.println(dl.toString()); dl.deleteNode(dl.findKthNode(dl.size())); StdOut.println(dl.toString()); } }
未完