1.3 背包、队列和栈

知识点

背包:只进不出,迭代顺序不确定(即无先后顺序)

队列:先进先出

栈   :后进先出

两种基础数据结构:数组和链表

数据结构 优点 缺点
数组 通过索引可以访问任意元素 在初始化时就需要知道元素的数量
链表 使用的空间大小和元素数量成正比 需要通过引用访问任意元素


练习

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());
    }
}



未完

				
时间: 2024-10-06 10:50:56

1.3 背包、队列和栈的相关文章

数据结构之背包,队列,栈

1:数据抽象 概念: 抽象数据类型,是一种能够对使用者隐藏数据表示的数据类型,抽象数据类型之所以重要,是因为他在程序设计上支持封装. 本节目标:本节将介绍三种抽象类型,用java实现,背包,堆栈,队列等最简单的数据结构. 背包   背包是一种不支持从中删除元素的集合数据类型.他的目的就是帮助用例手机元素并迭代遍历所有收集到的元素.API图示参考1.1 import java.util.Iterator; import java.util.NoSuchElementException; /** b

编程题目: 两个队列实现栈(Python)

感觉两个队列实现栈 比 两个栈实现队列 麻烦 1.栈为空:当两个队列都为空的时候,栈为空 2.入栈操作:当队列2为空的时候,将元素入队到队列1:当队列1位空的时候,将元素入队到队列2: 如果队列1 和 队列2 都为空的时候,那就选择入队到队列1. 3.出队操作:当两个队列都为空的时候,引发错误"栈为空": 当队列2位空的时候,如果队列1中只有一个元素,则直接将队列1中的元素出队: 如果队列1不止一个元素的时候,就将队列1的元素出队然后入队到队列2,知道队列1中只有一个元素,然后将队列1

C语言算法系列---1.队列和栈

写在前面:在家玩了好久,实在是不知道干嘛了,突然想找些事做,现在是时候做些什么了.这些东西不见得多高深,也可能很简单,但很基础,也无法忽视.同时,也是自己学习走过的一条路. 这是开头,就写写C的队列和栈的一些算法吧. 首先是栈的一些基础功能的实现,先贴代码: #include<stdlib.h> #include<stdio.h> typedef int SElemType; //声明栈元素类型为int typedef int Status; //函数返回值的类型为int #def

剑指Offer面试题7(Java版):用两个栈实现队列与用两个队列实现栈

题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deletedHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能. 我们通过一个具体的例子来分析该队列插入和删除元素的过程.首先插入一个元素a,不妨先把它插入到stack1,此时stack1 中的元素有{a},stack2为空.再压入两个元素b和c,还是插入到stack1中,此时stack1中的元素有{a,b,c},其中c位于栈顶,而stack2仍然为空. 这个时候,我们试着删除从队列中删除一个元素.

数据结构(7)----栈与队列之栈的应用四则运算表达式求值

栈与队列之栈的应用四则运算表达式求值 栈在四则运算表达式求值的应用为逆波兰表达式(后缀表达式) 普通算式(中缀表达式):9 + (3 - 1) * 3 + 10 / 2     ---(1) 逆波兰表达式(后缀表达式):9 3 1 - 3 * + 10 2 /         ---(2) 1:逆波兰表达式的计算规则 从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到符号,就将处于栈顶的两个数字出栈,进行运算,再把运算结果进栈,一直到最终获得结果.接下来我们以(2)式为例:

数组的队列和栈方法

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>数组的队列和栈方法</title></head><body><script>// 栈是一种LIFO(Last-In-First-Out后进先出)的数据结构,js中的push()和pop()类似栈的行为// 队列是一种FIFO(

【JavaSE】day05_List集合_List排序_队列和栈

1.List集合 1)有序集,可重复集.List的特点是可以像数组一样,根据下标操作元素.所以List提供了一些独有的方法. 2)常用实现类: --ArrayList:内部由数组实现,查询快. --LinkedList:内部由链表实现,增删快. 3)E get(int index) 获取指定下标对应的元素.(下标从0开始) 4)E set(int index,E e) 将给定的元素设置到指定的位置上,返回值为原位置上的元素.所以该操作是替换元素操作. 注:需在现有的元素上进行操作. 代码演示:

关于队列与栈相互模拟的读书笔记

栈与队列都是比较高级的数据结构,虽然不难,但有时有些问题也比较灵活,在<编程之美>与<剑指offer>上就有一些这样的题目.用队列模拟栈.用站栈模拟队列,以及现实队列与栈的最大值与最小值求解,这些都是基础的,只要理解栈的后进先出与队列的先进先出特点即可解决. 1.栈模拟队列 用两个栈,元素从一个栈stackA进入,从另一个栈stackB出来.进队列时直接添加到stackA,出队列时若stackA非空,则直接出,否则将stackB中元素全部初战装到stackA,然后从stackA出栈

算法系列(六)数据结构之表队列和栈

在http://blog.csdn.net/robertcpp/article/details/51559333一文中,我们讲了排序,这一章来介绍一下基本数据结构:表.队列.栈和它们的简单实现 一.表ADT 1.数组实现顺序表 通过对数组操作,来直接对表进行增删查改操作,这种线性表查找某个位置的元素花费的时间为O(1),但是插入删除元素花费的时间为O(n),如果对表的操作更多的是访问操作,那么选择这种实现更为合适. 下面是一个简单实现 package com.algorithm.list; im