09考研数据结构试题的一种解法(Java版)

本文为原创,如需转载,请注明作者和出处,谢谢!   

    虽然研究生已毕业,但看到有一些难度的研究生考试题还是忍不住要做做,本文给出了09年研究生入学考试的一道数据结构题的Java实现。该题的描述如下图所示。

    该题的两种实现一位朋友已经完成了,详见递归和非递归实现 。在本文将给出另外一种算法,该算法的空间复杂度为O(1),时间复杂度为O(n)。这在空间复杂度和时间复杂度上应该是比较优化了。
    本算法的基本思想如下:
   
既然是查找倒数第K个结点(注意,不是正数,否则就没什么可讨论的了),而且链表是单向的,还不能改变表结构,这就意味着只能从前往后扫描结点。我们首先
要知道这个链表有多少个结点(如果总结点数都不知道,何谈倒数?),这个非常简单,只要从头扫描一下链表,再计一下数即可。
   
在同一时间从事多项工作会大大提升效率,当然,扫描链表也不例外,在扫描链表的同时,还需要做一些其他的工作。既然只能从前向后扫描链表,而且要求倒数第
K个结点,那就让我们把这个链表按长度为K分成若干块,而最后扫描的结果要么结点数是K的整数倍(模为0),要么余数(模)不为0(多出几个结点,多出的
结点数小于K)。
    先看看第二种情况。
    假设有12个结点的链表,每一个结点的值从前往后分别是1至12,如下所示:

    1  2  3  4  5  6  7  8  9  10  11 12

    假设我们要求倒数第5个结点,我们直接就可以看出结果是8。那么用程序如何处理呢?
   
    先按长度为5将上面的结点分成三个区域,如下:

    1 2 3 4 5           6 7 8 9 10           11 12

    注意,不是物理分,而是使用变量来保存区域的边界(也就是区域最后一个结点的对象)。
    从上面的分隔可以看出,最后剩下两个结点,既然是求倒数第5个,而最后剩下了两个,那么还缺5-2=3个,因此,只需要从倒数第二个块(6 7
8 9
10)略过前两个,第三个结点(8)就是我们要求的结果,而5就是题中的k,2就是结点数与k的模,因此,可以推出一个公式,倒数第k个结点就是按长度为
k按分成的若干块中的第二块的第(结点数 % k+ 1)个结点。
    下面来看看(结点数 % k)为0的情况。假设上面的例子中的k为4,正确的输出结果应为9,分块如下:

    1 2 3 4      5 6 7 8      9 10 11 12

    从上面的三个块可以看出,结果正好是最后一个块的第一个结点,这时mod为0(mod=结点数 % k),因此,在这种情况也可以使用上面的公式,只是变成了最后一个块。

   
根据上面的基本思想可以设两个指针,p1和p2,其中p1最终指向倒数第2个完整块,p2最终指向倒数第1个完整块,对于第一种情况,p1指向5,p2指
向10,这时可以使p1向后移动(k -
mod)个结点即可(从5移动3个正好是8)。而对于第二种情况,p1指向8,p2指向12,而mod=0,这时的结果仍然是mod+1,也就是p1向后
移动1个结点就是所求的结果。
为了满足(k=结点数)的情况,需要将p1的初始值设为头结点,这样如果(k=结点数),就直接从头结点向后移动一个结点就是最后的结果,如上面的例子求
倒数第12个结点,也就是求正数第1个结点。

    下面是这个算法的具体实现(包括核心算法、生成链表及调用核心算法的代码):

public class Test
{
    static class Node
    {
        public int data;
        public Node nextNode;
    }
    //////////////////////////////////////////
    //  核心算法
    private static int findNode(Node headNode, int k)
    {
        Node p = headNode, p1 = headNode, p2 = null; 
        int count = 0;  //  表示结点数
        while (p.nextNode != null)
        {
            p = p.nextNode;
            count++;
            //  遇到k的整数位个结点,进行分块
            if (count % k == 0)
            {                
                if (p2 != null)
                    p1 = p2;
                p2 = p;
            }
        }
        //  k超过链表结点数,未找到,返回0
        // 此处也可以用k > count来判断
        if (p2 == null) 
        {
            return 0;
        }
        else
        {
            int mod = count % k;
            int offset = mod + 1;  // 任何情况下,最终结果都是p1指向的结点向后移动(mod + 1)个结点
            for (int i = 0; i < offset; i++)
                p1 = p1.nextNode;
            System.out.println(p1.data);
            return 1;
        }
    }
    ////////////////////////////////////////
    public static void main(String[] args) throws Exception
    {
        //产生一个包含1个头结点和120个结点的链表
        Node headNode = new Node();
        Node p = headNode;
        for (int i = 0; i < 120; i++)
        {
            p.nextNode = new Node();
            p.nextNode.data = i + 1;
            p = p.nextNode;
        }
        p.nextNode = null;
        //  开始查找倒数第k个结点,如果找到,返回1,并输出结点的data值
        System.out.println(findNode(headNode, 12));
    }
}

    上面程序的输出结果如下:

    109
    1

    读者也可以使用其他的测试用例来测试上面的程序。

    本算法从空间复杂度O(1)和时间复杂度O(n)的综合指标基本上算是比较优化了,如果哪位读者还有更简单和快速的算法,请跟贴!!

时间: 2024-09-24 05:48:48

09考研数据结构试题的一种解法(Java版)的相关文章

算法系列(六)最长公共子序列(LCS)问题(连续子序列)的三种解法

最长公共子序列(LCS)问题有两种方式定义子序列,一种是子序列不要求不连续,一种是子序列 必须连续.上一章介绍了用两种算法解决子序列不要求连续的最终公共子序列问题,本章将介绍要求 子序列必须是连续的情况下如何用算法解决最长公共子序列问题. 仍以上一章的两个字符串 "abcdea"和"aebcda"为例,如果子序列不要求连续,其最长公共子序列为"abcda",如果子序列 要求是连续,则其最长公共子序列应为"bcd".在这种情况下

java-标签管理的数据结构,用哪种最优?

问题描述 标签管理的数据结构,用哪种最优? 浏览器中的收藏夹,用keyword来管理的,一个收藏夹项目,可以有多个keyword,现在要查出所有同时具有<中国>和<新闻>两个关键词的项目 这种问题,用什么数据结构比较好?不用数据库的话 解决方案 不用数据库,就用localstorage,数量量小没问题,逗号分隔关键字,按行分隔不同的网页. 解决方案二: 可以保存在txt文件中,也可以建一个serializable的类,然后保存信息到它的一个实例中,java可以保存这个实例到文件 解

蓝桥杯试题 大臣的旅费 求java解法

问题描述 蓝桥杯试题 大臣的旅费 求java解法 :大臣的旅费 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达.同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的. J是T国重要大臣,他巡查于各大城市之间,体察民情.所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情.他有一个钱袋,用于存放往来城市间的路

c++-关于自学考试北大 计算机及应用(独立本科)实践课上机 C++ 数据结构 试题

问题描述 关于自学考试北大 计算机及应用(独立本科)实践课上机 C++ 数据结构 试题 请问试题类型是什么样子的,要编整个程序吗,还是试卷给个整体代码然后填空的那种或者改错的那种??

学生党如何拿到阿里技术offer: 《阿里巴巴常考面试题及汇总答案(Java方向)上篇》

之前和大家分享了几位学长学姐们在阿里面试的经验,他们其中有成功的,也有留下遗憾的.但是总之,我认为作为技术人员,首先打铁需要自身硬,在学校里不光要学精学透基础的专业知识,还要有过硬的编程能力,当然我们所谓的计算机软件的科班出身更不能将自己定位为所谓的程序而应该是软件攻城狮-这样我们要对自己有一个比较高的要求,记得有一个计算机大牛曾说过"Talk is cheap,show me the code!",的确与其空谈,不如实干,多看书,多思考,多动手编程,多参与项目实践. 好了,今天就不多

首页四格,首页五格For6.0(GBK)(UTF-8)[12种组合][9-18][版主安装测试通过]_php实例

下载万次的首页四格,首页五格For6.0(GBK)(UTF-8)[12种组合][9-18][版主安装测试通过] 引用: 本插件由版主sakurakawaii于07年9月8日15:30分 在Windows XP Discuz!6.0.0标准模版 IE6 Mysql4.1下测试安装无错 本测试仅代表此插件安装无错,不包括今后长期使用中可能出现的问题引用: 声明:本程序引用了部分5.0四格的代码,若是源码作者有意见请短信我,一定删除发布! 经过大量修改和flash设置增加了好多自定义设置,此插件可以说

java类的问题-java版 数据结构课程设计 通讯录的制作

问题描述 java版 数据结构课程设计 通讯录的制作 A.通讯录的制作 要求每条信息至包含姓名(name )城市(city)电话(tel)QQ号(qq),完成如下功能: (1) 输入信息-- enter(); (2) 显示信息--display( ); (3) 查找以姓名作为关键字 --search( ); (4) 删除信息--delete( ); (5) 存盘(将数据保存在文件或者数据库中)--save ( );

5种解决Java独占写文件的方法_java

本文实例讲解了5种解决Java独占写文件的方法,包含自己的一些理解,如若有不妥的地方欢迎大家提出. 方案1:利用RandomAccessFile的文件操作选项s,s即表示同步锁方式写 RandomAccessFile file = new RandomAccessFile(file, "rws"); 方案2:利用FileChannel的文件锁 File file = new File("test.txt"); FileInputStream fis = new Fi

网上考试系统编制中的随机抽取试题的四种算法

算法|随机 因为教学的需要,我决定编写一个asp+ms sql2000的网上考试系统,其功能主要为:实现判断题.单项多项选择题和填空题的在线自动答题.改卷:并将学生的错误答案记入数据库,供教师分析.在编写从题库中随机抽取试题这一模块的算法上,却颇费了一番周折,现将解决过程记录如下,以供大家参考. 为了便于说明问题,文中提供的代码中的变量pd为从题库中要抽取出来考试的试题数量,数据库表名与字段名我都使用了中文,并仅以判断题为例. 算法一 由于不知道如何实现从题库中随机抽取试题的sql语句,我在网上