算法(Algorithms)第4版 练习 链表类 1.3.19~1.3.29

package com.qiusongde.linkedlist;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class LinkedList<Item> implements Iterable<Item> {

    private Node<Item> first;

    //Node should be public static in this class
    //When it comes to LinkedList, Node should be accessed outside
    public static class Node<E> {
        public E item;
        public Node<E> next;
    }
    /**
     * initialize LinkedList
     */
    public LinkedList() {
        first = null;
    }

    public LinkedList(Node<Item> first) {
        this.first = first;
    }

    /**
     * insert item at the beginning of the list
     * @param item the item to be inserted
     */
    public void insertAtBeginning(Item item) {

        Node<Item> oldfirst = first;

        first = new Node<Item>();
        first.item = item;
        first.next = oldfirst;

    }

    /**
     * remove the item at the beginning of the list
     * @return return the item at the beginning of the list
     * @throws NoSuchElementException if this Linked List is empty
     */
    public Item removeFromBeginning() {

        if(isEmpty())
            throw new NoSuchElementException("LinkedList is empty");

        Item item = first.item;
        first = first.next;

        return item;
    }

    //1.3.19
    /**
     * remove the last node in the linked list whose first node is first
     *
     * @return return the item of the last node
     * @throws NoSuchElementException if this Linked List is empty
     */
    public Item removeTheLast() {

        Node<Item> precurrent;
        Item item = null;

        precurrent = findPreLastNode();

        //has not found
        if(precurrent.next == null) {
            throw new NoSuchElementException("LinkedList is empty");
        }

        item = precurrent.next.item;
        //some implementation will add one empty node as head, and head.next = first
        //if so, it‘s not necessary to have if condition here
        if(precurrent.next == first)
            first = first.next;
        else
            precurrent.next = precurrent.next.next;

        return item;
    }

    /**
     * return the previous last node
     *
     * @return return the previous last node.
     * If the last node is the first node, the previous last node is a virtual one
     */
    private Node<Item> findPreLastNode() {

        Node<Item> precurrent = new Node<Item>();
        precurrent.next = first;

        //find the previous last node
        //precurrent.next is the same as current
        while(precurrent.next != null && precurrent.next.next != null) {
            precurrent = precurrent.next;
        }

        return precurrent;
    }

    //1.3.20
    /**
     * delete the kth element in a linked list, if it exists.
     *
     * @param k the kth element, it should larger than 1
     * @throws IllegalArgumentException if k < 1
     * @throws NoSuchElementException if the size of the list is less than k
     */
    public Item delete(int k) {

        if(k < 1)
            throw new IllegalArgumentException("k must larger than 1");

        Node<Item> precurrent = new Node<Item>();
        precurrent.next = first;
        Item item;

        while(precurrent.next != null && k > 1) {
            precurrent = precurrent.next;
            k--;
        }

        if(precurrent.next == null)
            throw new NoSuchElementException("LinkedList hasn‘t so many elements");

        item = precurrent.next.item;
        if(precurrent.next == first)
            first = precurrent.next.next;
        else
            precurrent.next = precurrent.next.next;

        return item;
    }

    //1.3.21
    /**
     * find if some node in the list has key as its item field
     *
     * @param list the linked list of T
     * @param key the T key
     *
     * @return {@code true} some node exists.
     *          {@code false} no node exist
     */
    public static <T> boolean find(LinkedList<T> list, T key) {

        for(T s : list) {
            if(s.equals(key))
                return true;
        }

        return false;
    }

    //1.3.24
    /**
     * remove the node following the node x
     * (and does nothing if the argument or the next field in the argument node is null)
     *
     * @param x the given node
     */
    public static <T> void removeAfter(Node<T> x) {

        if(x == null || x.next == null)
            return;

        Node<T> current = x.next;
        x.next = null;

        while(current != null) {
            Node<T> temp = current.next;
            current.next = null;
            current = temp;
        }

    }

    //1.3.25
    /**
     * insert the second node after the first on its list.
     * and does nothing if either argument is null.
     *
     * @param first the first node
     * @param second the second node to be inserted after the first
     */
    public static <T> void insertAfter(Node<T> first, Node<T> second) {

        if(first == null || second == null)
            return;

        second.next = first.next;
        first.next = second;

    }

    //1.3.26
    /**
     * remove all of the nodes in the list that have key as its item field
     *
     * @param list the linked list of T
     * @param key the T key
     *
     * @return void
     *
     */
    public static <T> void remove(LinkedList<T> list, T key) {
        Node<T> precurrent;
        precurrent = findPreNode(list, key);

        //remove all of the nodes
        while(precurrent.next != null) {

            if(precurrent.next == list.first)
                list.first = list.first.next;
            else
                precurrent.next = precurrent.next.next;

            precurrent = findPreNode(list, key);
        }

    }

    //1.3.26
    /**
     * find the node in the list whose item equals key
     *
     * @param key the T key
     *
     * @return return the previous node whose item equals key
     */
    private static <T> Node<T> findPreNode(LinkedList<T> list, T key) {
        Node<T> precurrent = new Node<T>();
        precurrent.next = list.first;

        while(precurrent.next != null && !precurrent.next.item.equals(key)) {
            precurrent = precurrent.next;
        }

        return precurrent;
    }

    //1.3.27
    /**
     * return the value of the maximum key in the list
     *
     * @param list the linked list of Integer
     *
     * @return return the maximum key in the list
     */
    public static int max(LinkedList<Integer> list) {

        if(list.first == null)
            return 0;

        int max = 0;
        for(int val : list) {
            if(val > max)
                max = val;
        }

        return max;
    }

    //1.3.28
    /**
     * return the value of the maximum key in the list by recursion
     *
     * @param list the linked list of Integer
     *
     * @return return the maximum key in the list
     */
    public static int maxByRecursion(LinkedList<Integer> list) {

        if(list.first == null)
            return 0;

        int first = list.first.item;//first item
        list.first = list.first.next;//remove first item in the list
        int max = maxByRecursion(list);//calculate the maximum value of the new list

        if(first > max)
            return first;
        else
            return max;
    }

    /**
     *
     * see if the list is empty
     *
     * @return true if the list is empty.
     * false if the list isn‘t empty
     */
    public boolean isEmpty() {
        return first == null;
    }

    @Override
    public String toString() {
        String s = "";

        Node<Item> temp = first;

        while(temp != null) {
            Item item = temp.item;
            s += item + " ";
            temp = temp.next;
        }

        return s;
    }

    @Override
    public Iterator<Item> iterator() {
        return new ListIterator();
    }

    private class ListIterator implements Iterator<Item> {

        private Node<Item> current = first;

        @Override
        public boolean hasNext() {
            return current != null;
        }

        @Override
        public Item next() {
            if(!hasNext())
                throw new NoSuchElementException();

            Item item = current.item;
            current = current.next;

            return item;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

    }

}
时间: 2024-12-30 02:17:13

算法(Algorithms)第4版 练习 链表类 1.3.19~1.3.29的相关文章

数据结构与算法系列(1)-单链表类的实现(C++)

通过定义一个C++类封装单链表这种数据结构, 封装的方法有: 1.通过输入创建单链表: 2.获取单链表的数据元素个数: 3.打印输出单链表中各个元素: 4.搜索某个元素在单链表中的位置: 5.在某个位置之后插入一个结点: 6.在某个位置删除一个节点: 7.单链表逆置: 8.单链表是否存在回环的判定: 9.单链表的升序排序: 10.两个单链表的升序合并: 11.两个单链表的降序合并. 注:单链表的排序采用的是快速排序的方法. 下面是C++写的程序代码,附运行截图. #include <iostre

1.3 Bags, Queues, and Stacks(算法 Algorithms 第4版)(一)

1.3.1 package com.qiusongde; import java.util.Iterator; import java.util.NoSuchElementException; import edu.princeton.cs.algs4.StdIn; import edu.princeton.cs.algs4.StdOut; public class FixedCapacityStackOfStrings implements Iterable<String> { privat

数据结构与算法之PHP实现链表类(单链表/双链表/循环链表)

链表是由一组节点组成的集合.每个节点都使用一个对象的引用指向它的后继.指向另一个节点的引用叫做链. 链表分为单链表.双链表.循环链表. 一.单链表 插入:链表中插入一个节点的效率很高.向链表中插入一个节点,需要修改它前面的节点(前驱),使其指向新加入的节点,而新加入的节点则指向原来前驱指向的节点(见下图). 由上图可知,B.C之间插入D,三者之间的关系为 current为插入节点的前驱节点 current->next = new              // B节点指向新节点D new->n

算法(第4版)-1.4.9 内存

总结:本小节讲述了Java的内存分配机制以及各种数据结构所使用的内存量. 重点: 1. 计算机中的电路很大一部分的作用就是帮助程序保存一些值并在稍后取出它们. 2. 计算机上的Java对内存的使用经过了精心的设计(程序的每个值在每次运行时所需的内存量都是一样的),但实现了Java的设备非常多,而内存的使用是和实现相关的. 3. 原始数据类型的常见内存.需求见算法(第4版)-1.1.2 原始数据类型与表达式. 4. · 对象本身的开销:16字节 · 对象的引用(内存地址):8字节 · 一般内存的使

ubuntu命令行下java工程编辑与算法(第四版)环境配置

ubuntu命令行下java工程编辑与算法(第四版)环境配置 java 命令行 javac java 在学习算法(第四版)中的实例时,因需要安装配套的java编译环境,可是在编译java文件的时候总是出各种错误,特在此总结一下. ubuntu下java环境配置 由于网上教程比较多,而且也较全面,特此摆放一个链接,跟着此教程总就可以配置好oracle的java jdk,如果想更加省事,直接在命令行下键入java,会提示安装各种开源java jdk,只需要一个命令即可: sudo apt-get i

算法(第4版)PDF下载

网盘下载地址:算法(第4版)PDF下载 – 易分享电子书PDF资源网 作者: 塞奇威克 (Robert Sedgewick) / 韦恩 (Kevin Wayne) 出版社: 人民邮电出版社 原作名: Algorithms 4th edition 译者: 谢路云 出版年: 2012-10-1 页数: 636 定价: 99.00元 装帧: 平装 内容简介 · · · · · · 本书全面讲述算法和数据结构的必备知识,具有以下几大特色. ? 算法领域的经典参考书 Sedgewick畅销著作的最新版,反

排序算法总结(C语言版)

1.    插入排序 1.1     直接插入排序 1.2     Shell排序 2.    交换排序 2.1     冒泡排序 2.2     快速排序 3.    选择排序 3.1     直接选择排序 3.2     堆排序 4.    归并排序 4.1     二路归并排序 4.2     自然合并排序 5.    分布排序 5.1     基数排序 1.插入排序 1.1      直接插入排序 将已排好序的部分num[0]~num[i]后的一个元素num[i+1]插入到之前已排好序的

每天一个小算法(3)----倒序打印链表

这个比较简单,用栈.递归.倒转链表都可以实现,不再过多解释. 代码使用递归实现 1 #include <stdio.h> 2 #include <time.h> 3 #include <stdlib.h> 4 typedef struct Node 5 { 6 int data; 7 Node* next; 8 }Node, *List; 9 10 11 List createList(int num) //随机生成数字,构造链表 12 { 13 List aList

算法(第四版)C#题解&mdash;&mdash;1.3.49 用 6 个栈实现一个 O(1) 队列

因为这个解法有点复杂,因此单独开一贴介绍. <算法(第四版)>中的题目是这样的: 1.3.49 栈与队列.用有限个栈实现一个队列,保证每个队列操作(在最坏情况下)都只需要常数次的栈操作. 那么这里就使用六个栈来解决这个问题. 这个算法来自于这篇论文. 原文里用的是 Pure Lisp,不过语法很简单,还是很容易看懂的. 先导知识--用两个栈模拟一个队列 如何使用两个栈来模拟一个队列操作? 这是一道很经典的题目,答案也有很多种,这里只介绍之后会用到的一种方法. 首先我们有两个栈,H 和 T,分别