数据结构中gethead((a))=(a),为什么不是=a,数据结构tail和head

文章 2年前 (2021) admin
0

Q1:数据结构中Gethead((a,b),(c,d)))的结果是什么啊?我头都晕啦

我不知道你的意思,但是有两种解释。1.Gethead((a,b),(c,d))是一个逗号运算,结果是(b,(c,d))==(b,d)==(d)。(c,d)) gethead (((a,b)、(c,d))=gethead (a)因此表a是一个具有两个元素(分别是两个子表(a,b)和(c,d))的广义表,然后gethead (((a,b))。

Q2:数据结构的问题~

练习1,选择题1计算机算法必须具备输入、输出和()等五个特征。a可行性、可移植性和可扩展性b可行性、确定性和有限性c确定性、有限性和稳定性d可读性、安全性和稳定性2在数据结构中,数据结构在逻辑上可分为()a动态结构和静态结构b紧凑结构和非紧凑结构c内容结构和外部结构d线性结构和非线性结构3以下程序段的时间复杂度为()数量级For(I=1;I=n;I)对于(j=1;j=I;j)对于(k=1;k=j;k)x=x 1;O (1) b o (n) c o (N2) d o (n3) 4在数据结构中,与计算机无关的使用的是数据()结构a逻辑b存储c逻辑和存储d物理5计算机中数据结构的表示是指()a数据逻辑结构b数据结构c数据存储结构d数据元素之间的关系6以下()具有最佳的时间复杂度,即最短的执行时间。O (n) b o (logn) c o (nlogn) d o (N2) 7、下列程序段的时间复杂度为数量级()。Int fun(int n){I=1,s=1;While(s、}(2) B=(K,R),其中k={a,B,c,d,e,f,g,h} r={r} r={,}(3)B=(K . K=2;而(ij)j=j ^ 1;否则I=I ^ 1;(3)x=91;y=100 while(y0)If(X100){ x=x-10;y=y-1;} else x=x ^ 1;练习1。选择题1线性表是()a一个有限序列,可以是空白b一个有限序列,不能是空白c一个无限序列,可以是空白d一个无限序列,不能是空白2在长度为n的序列表中,在第二个元素(1In ^ 1)的位置插入新元素时,需要从后向前依次向后移动()个元素。A-IBN-I1CN-I-1DI3在序列表的末尾插入一个元素,时间多重数的数量级为()。A (n) b o (1) c o (N2) d o(对数n) 4是一个长度为n的线性表,当任意位置插入或删除一个元素的概率相等时,插入一个元素所需的移动元素的平均数为(),删除一个元素所需的移动元素的平均数为()a(n-1)/2b n c(n . P-next=P-next-next b P=P-next c P=P-next c P=P-next-next d next=P6单链表的存储密度为()。A > 1 B=5 C <1。

D 不能确定  7 在一个单链表中,若要在p所指向的结点之后插入一个新结点,则需要相继修改( )个指针域的值。  A 1 B 2 C 3 D 4  8 在一个单链表中,若要在p所指向的结点之前插入一个新结点,则此算法的时间复杂度的量级为( )。  A O(n) B O(n/2) C O(1) D O(n1/2)  9 在一个带头结点的双向循环链表中,若要在p所指向的结点之前插入一个新结点,则需要相继修改( )个指针域的值。  A 2 B 3 C 4 D 6  二、简答题  1 什么叫线性表?它有哪些特点?  2 在链表的设计中,为什么通常采用带头结点的链表结构?  3 对比顺序表与单链表,说明顺序表与单链表的主要优点和主要缺点。  4 试编写算法实现顺序表的逆置,即把顺序表A中的数据元素(a1,a2, …,an)逆置为(an,an-1, …,a1)。  5 已知A和B为两个非递减的线性表,现要求实现如下操作:从A中删除在B中出现的元素。试编写在顺序表中实现上述操作的算法。  6 试编写算法实现链表的就地逆置(不增加存储空间),即把链表A中的数据元素(a1,a2, …,an)逆置为(an,an-1, …,a1)。  7 假设有两个非递减的线性表A 和B,均采用链式存储结构,试编写算法将A和B 归并成一个按元素非递减的线性表C。  8 试编写算法求单循环链表的表长。  习题3  一、选择题  1在栈顶一端可进行的全部操作是( )。  A 插入 B 删除 C插入和删除 D进栈  2 栈的特点是( )。  A 先进先出 B 后进先出 C后进后出 D不进不出  3 顺序栈是空栈的条件是( )。  A top==0 B top==1 C top==-1 D top==m  4 假定利用数组A[N]顺序存储一个栈,top表示栈顶指针,已知栈未满,则x入栈时所执行的操作是( )。  A a[--top]=x; B a[top--]=x C a[++top]=x D a[top++]=x  5 一个栈的入栈序列是a,b,c,d,e,则不可能的出栈序列是( )。  A edcda B dceab C decba D abcde  6 经过下列栈的运算后EmptyStack(s)的值是( )。  InitStack(s);Push(s,a);Push(s,b);Pop(s,x);Pop(s,x) ;  A a B b C 1 D 0  7 若已知一个栈的入栈序列是1,2,3, …,n,其输出序列为p1,p2,p3,…,pn,若p1=n,则pi为( )。  A i B n-i C n-i+1 D 不确定  8 队列的特点是()。  A 先进先出 B 后进先出 C先进后出 D 不进不出  9 循环队列S为满的条件是()。  A S->rear==S->front  B S->rear+1)%maxsiae==s->front  C S->rear==0  D s->front==0  10 经过下列运算后GetHead(Q)的值是()。  InitQueue(Q); EnQueue(Q,a); EnQueue(Q,b); DeQueue(Q,x);  A a B b C 1 D 2  二、简答题  1 简述栈与队列的相同点与不同点。  2 在顺序队列中,什么叫真溢出?什么叫假溢出?为什么顺序队列常都采用循环队列结构?  3 设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(不设头指针),试编写相应的入队列、出队列算法。  4 设计一个输出如下形式数值的递归算法。  4 4 4 4  3 3 3  2 2  1  5 编写一个算法,利用栈的基本运算返回指定栈中的栈底元素。  习题4  一、选择题  1 串是一种特殊的线性表,其特殊性体现在( )  A 唯一可以顺序存储 B 数据元素是一个字符  C 可以链接存储 D 数据元素可以是多个字符  2 下面( )是C语言中“abcd321ABCD”的子串。  A abcd B 321AB C “abcAB” D “21AB”  3 设有两个串p和q,求p和q首次出现的位置的运算称作( )  A 连接 B 模式匹配 C 求子串 D 求串长  4 设有一个字符串S=“windows”,求子串的数目是()  A 25 B 26 C 27 D 28  二、简答题  1 空串与空格串有什么区别?字符串中的空格有什么意思?空串在串的处理中有什么作用?  2串是由字符组成的,长度为1的串和字符是否相同?为什么?  3简述串的静态顺序存储结构与动态顺序存储结构有什么区别,分别写出它们的结构体定义。  4字符串采用静态顺序存储结构。编写一个算法删除S中地i个字符到第j个字符。  5编写一个算法判断s2是否是s1的子串。  习题5  一、选择题  1.二维数组A行下标i的范围从1到12,列下标j的范围从3到10,采用行序为主序存储,每个数据元素占用4个存储单元,该数组的首地址(即A[1][3]的地址)为1200,则A[6][5]的地址为( )。  A 1400 B 1404 C 1372 D 1368  2.二维数组M的元素是4个字符(每个字符占一个存储单元)组成的串,行下标i的范围从0到4,列下标j的范围从0到5,M按行存储时元素M[3][5]的起始地址与M按列存储时元素( )的起始地址相同。  A M[2][4] B M[3][4] C M[3][5] D M [4][4]  3.数组A中,每个元素A的长度为3个字节,行下标i从1到5,列下标j从1到6,从首地址开始连续存放在存储器内,存放该数组至少需要的单元数是( )。  A 90 B 70 C 50 D 30  4.设有10阶矩阵A,其对角线以上的元素aij均取值为-3,其他矩阵元素为正整数,现在将矩阵A压缩存放在一维树组F[m]中,则 m为( )。  A 45 B 46 C 55 D 56  5.若广义表A满足head(A)=tail(A),则A为( )。  A ( ) B (()) C ((),()) D ((),(),())  6.递归函数f(n)=f(n-1)+n(n>1)的递归出口是( )  A f(1)=0 B f(1)=1 C f(0)=1 D f(n)=n  二、简答题  1.什么叫二维数组的行序优先存储?什么叫二维数组的列序优先存储?  2.什么样的矩阵叫特殊矩阵?特殊矩阵压缩存储的基本思想是什么?  3.什么样的矩阵叫稀疏矩阵?稀疏矩阵压缩存储的基本思想是什么?  三、计算题  设有二维数组A(6*8),每个元素占4个字节,A[0][0]的起始地址为1000,计算  (1) 数组A共占多少个字节;  (2) 数组的最后一个元素A[5][7]的起始地址;  (3) 按行优先存放时,元素A[1][4]的起始地址;  (4) 按列优先存放时,元素A[4[7]的起始地址;  四、设计题  1.对于二维数组A[m][n],其中m<=80,nleft=NULL B、t->ltag=1 C、t->ltag=1且t->left=NULL D、以上都不对  5、设高度为h的二叉数上只有度为0和度为2的结点,则此类二叉树中所包含的结点数至少为( )  A、2h B、2h -1 C、2h +1 D、h+1  6、已知某二叉树的后序遍历序列是dabec,中序遍历序列是debac,它的前序遍历序列是( )  A、acbed B、 decab C、 deabc D 、cedba  7、按照二叉树的定义,具有三个节点的二叉树有( )种  A、3 B、4 C、5 D、6  8、任意一棵二叉树的叶结点在先序、中序和后序遍历序列中的相对次序( )  A、不发生改变 B、发生改变 C、不能确定 D、以上都不对  9、对一个满二叉树,它有m个树叶,n个结点,深度为h,则()  A、n=h+m B 、h+m=2n C、m=h-1 D 、n=2h-1  二、设计题  1、已知一棵树的边的集合表示为{(L,N),(G,K),(G,1),(G,M),(B,E),(B,F),(D,G),(D,H),(D,I),(D,J),(A,B),(A,C),(A,D)}。画出这棵树并回答下面问题:  (1) 树的根节点是哪个,哪些是叶子结点,哪些是非终端结点。  (2) 树的深度是多少,各个结点的层数是多少。  (3) 对于G结点,它的双亲结点、祖先结点、孩子结点、子孙结点、兄弟和堂兄弟分别是哪些结点。  2、给定二叉树的先序序列和中序序列,能否重构出该二叉树?给定二叉树的先序序列和后序序列呢?若不能,给出反例。  3、一棵深度为h的满二叉树具有如下性质:第h层上的结点都是叶结点,其余各层上每个结点都有m棵非空子树。若按层次从上到下,每层从左到右的顺序从1开始对全部结点编号,试计算:  (1)第k层结点数(1<=k<=h)。  (2)整棵树结点数  (3)编号为i的结点的双亲结点的编号  (4)编号为i的结点的第j个孩子结点(若有)的编号  4、若7个带权结点,其权值分别为3,7,8,2,6,10,14,试以它们为叶结点构造一棵哈夫曼树(请按照每个结点的左子树根结点的权小于等于右子树根结点的权的次序构造),度计算出带权路径长度WPL及该树的结点总数。  5、假设二叉数采用链式存储结构,编写一个算法释放该二叉树所占用的全部结点。  6、编写一个计算一棵二叉树T的高度算法。  7、二叉树采用二叉树链表的结构存储,设计一个算法求二叉树中指定结点的层数。  习题7  一、选择题  1、 在一个具有n个顶点的无向图中,要连接全部顶点至少需要( )条边。  A、n B、n+1 C、n-1 D、n/2  2、对于一个具有n个顶点的无向图,若采用邻接矩阵表示,则该矩阵的大小是( )  A、n B、(n-1)/2 C、n-1 D、n2  3、具有6个顶点的无向图至少应用( )条边才能确保是一个连通图。  A、5 B、6 C、7 D、8  4、n个顶点的强连通图的邻接矩阵中至少有( )个非零元素。  A、n-1 B、n C、2n-2 D、2n  5、在一个具有n个顶点的有向完全图中,所含的边数为( )  A、n B、n(n-1) C、n(n-1)/2 D、n(n+1)/2  6、在一个具有n个顶点和e条边的无向图的邻接矩阵中,表示边存在的元素(又称为有效元素)的个数为( )。  A、n B、ne C、e D、2e  7、在一个具有n个顶点和e条边的有向图的邻接表中,保存顶点单链接的表头指针向量大小至少为( )  A、n B、2n C、e D、2e  8、在一个具有n个顶点和e条边的无向图的邻接表中,边结点的个数为( )。  A、n B、ne C、e D、e  9、对于一个有向图,若一个顶点的度为k1,出度为k2,则对应逆邻接表中该顶点单链表中的边结点数为( )  A、k1 B、k2 C、k1-k2 D、k1+k2  10、采用邻接表存储的图的深度优先遍历算法类似于二叉树的( )  A、接层遍历 B、中序遍历 C、先序遍历 D、后序遍历  11、无向图G=(V,A),其中V={a,b,c,d,e}, A={,,,,,}  对该图进行扑拓排序,下面序列中( )不是拓扑序列。  A、adcbe B、dabce C、abdce D、abcde  12、G是一个非连通无向图,共有28条边,则该图至少有( )个顶点。  A、7 B、8 C、9 D、10  二、简答题  1、 对于一个有向图,不用拓扑排序,如何判定图中是否存在环?  2、 用邻接矩阵表示图时,矩阵元素的个数与顶点个数是否相关?与边数是否相关?  习题8  一、选择题  1、 若查找每个记录的概率均等,则在具有n个记录的连续顺序文件中采用顺序查找法查找一个记录,其平均查找长度ASL为( )  A、(n-1)/2 B、n/2 C、(n+1)/2 D、n  2、下面关于二分查找叙述正确的是( )  A、表必须有序,表可以顺序方式存储,也可以链表方式存储  B、表必须有序且表中数据必须是整型,实型或字符型  C、表必须有序,而且只能从小到大排序  D、表必须有序,且表只能以顺序方式存储  3、当在一个有序的顺序存储表上查找一个数据时,既可用折半查找,也可用顺序查找,但前者比后者的查找速度( )  A、必定快 B、不一定 C、在大部分情况下要快 D、取决于表递增还是递减  4、具有12个关键字的有序表,折半查找的平均查找长度为( )  A、3.1 B、4 C、2.5 D、5  5、当采用分块查找时,数据的组织方式为( )  A、数据分成若干块,每块内数据有序  B、数据分成若干块,每块内数据不必有序,但块间必须有序  C、数据分成若干块,每块内数据有序,每块内最大(或最小)的数据组成索引块  D、数据分成若干块,每块(除最后一块外)中数据个数需相同  6、既希望查找速度快又便于线性表动态变化的查找方法有()  A、顺序查找 B、折半查找 C、索引顺序查找 D、哈希法查找  7、分别以下序列构造二叉排序树,与用其他三个序列所构造的结果不同的是( )  A、(100,80,90,60,120,110,130) B、(100,120,110,130,80,60,90)  C、(100,60,80,90,120,110,130) D、(100,80,60,90,120,130,110)  二、简答题  1、 什么叫动态查找?什么叫静态查找?什么样的存储结构适宜于进行静态查找?什么样的存储结构适宜于进行动态查找?  2、 什么叫平均查找长度?写出平均查找长度的定义  三、设计题  1、 已知一个个数为12的数据元素序列为{Dec,Feb,Nov,Oct,June,Sept,Aug,Apr,May,July,Jan,Mar},要求(注意字母的大小是指字母的ASCII码数值大小):  (1) 按各数据元素的顺序构造一棵二叉排序树  (2) 设各数据元素的查找概率相等,给出该二叉排序树的平均查找长度。  2、 设有数据元素序列{11,23,35,47,51,60,75,88,90,102,113,126},用除留余数法构造哈希表,要求:  (1) 设计哈希表的长度取值为m;  (2) 画出用开放定址法的线性探查法解决哈希冲突的哈希表结构;  (3) 画出用链表法解决哈希冲突的哈希表结构。  习题9  一、选择题  1、设有1000个无序的元素,希望用最快的速度挑出其中前10个最大的元素,最好( )排序法。  A、起泡排序 B、选择排序 C、堆排序 D、希尔排序  2、在待排序的元素序列基本有序的前提下,效率最高的排序方法是( )  A、插入排序 B、选择排序 C、快速排序 D、希尔排序  3、一组记录排序码为(46,79,56,38,40,84),则利用堆排序的方法建立的初始堆为( )  A、79,46,56,38,40,80 B、84,79,56,38,40,46  C、84,79,56,46,40,38 D、84,56,79,40,46,38  4、排序方法中,从未排序序列中依次取出元素与已排序序列(初始时为空)中的元素进行比较,将其放入已排序序列的正确位置上的方法,称为( )  A、希尔排序 B、起泡排序 C、插入排序 D、选择排序  5、下述几种排序方法中,要求内存量最大的是( )  A、插入排序 B、选择排序 C、快速排序 D、归并排序  6、下列四种排序方法中,不稳定的方法是( )  A、直接插入排序 B、冒泡排序 C、归并排序 D、直接选择排序  二、设计题  1、对给定的j(1<=j<=n),要求在无序的记录区R[1…n]中找到按关键字自小到大排在第j个位置上的记录(即在无序集合中找到第j个最小元),试利用快速排序的划分思想编写算法实现上述的查找操作。  2、以单链表为存储结构,写一个直接选择排序算法。  3、改写快速排序算法,要求采用三者取中的方式选择划分的基准记录;若当前被排序的区间长度小于等于3时,无须划分而是直接采用直接插入方式对其排序。

Q3:数据结构 ,C语言,单链表头插入,语句看不懂请高手指教

1.在这个程序中,abc依次插入头节点之前,然后插入d。原始链接列表为空。2.当您第一次进入循环时,假设元素a被插入,然后a被存储在s中,并且s-next=head;就是在头部前面放一个,至于头部是否为空不影响结构。此时A是链表的头,链表中只有一个元素。链表结束的另一个标志是链表中元素的下一个为空。

Q4:c语言的问题高手进

1.错。如果我的算法只是用作来计算(中间计算),那为什么一定要输出?2.存储结构3.数据流4.如果你理解为定义的时候,那么形参只能是变量,使用的时候形参常量,变量和表达式都行。说形参必须为变量的同学建议加强下C++。举个最简单的列子:int sum(int a,int b){return a+b;}int main(){ int a; a=sum(3,4); cout<<a<<endl; return 0;}

Q5:java链表问题

链表是一种重要的数据结构,在程序设计中占有很重要的地位。C语言和C++语言中是用指针来实现链表结构的,由于Java语言不提供指针,所以有人认为在Java语言中不能实现链表,其实不然,Java语言比C和C++更容易实现链表结构。Java语言中的对象引用实际上是一个指针(本文中的指针均为概念上的意义,而非语言提供的数据类型),所以我们可以编写这样的类来实现链表中的结点。 class Node { Object data; Node next;//指向下一个结点 } 将数据域定义成Object类是因为Object类是广义超类,任何类对象都可以给其赋值,增加了代码的通用性。为了使链表可以被访问还需要定义一个表头,表头必须包含指向第一个结点的指针和指向当前结点的指针。为了便于在链表尾部增加结点,还可以增加一指向链表尾部的指针,另外还可以用一个域来表示链表的大小,当调用者想得到链表的大小时,不必遍历整个链表。下图是这种链表的示意图: 链表的数据结构 我们可以用类List来实现链表结构,用变量Head、Tail、Length、Pointer来实现表头。存储当前结点的指针时有一定的技巧,Pointer并非存储指向当前结点的指针,而是存储指向它的前趋结点的指针,当其值为null时表示当前结点是第一个结点。那么为什么要这样做呢?这是因为当删除当前结点后仍需保证剩下的结点构成链表,如果Pointer指向当前结点,则会给操作带来很大困难。那么如何得到当前结点呢,我们定义了一个方法cursor(),返回值是指向当前结点的指针。类List还定义了一些方法来实现对链表的基本操作,通过运用这些基本操作我们可以对链表进行各种操作。例如reset()方法使第一个结点成为当前结点。insert(Object d)方法在当前结点前插入一个结点,并使其成为当前结点。remove()方法删除当前结点同时返回其内容,并使其后继结点成为当前结点,如果删除的是最后一个结点,则第一个结点变为当前结点。 链表类List的源代码如下: import java.io.*; public class List { /*用变量来实现表头*/ private Node Head=null; private Node Tail=null; private Node Pointer=null; private int Length=0; public void deleteAll() /*清空整个链表*/ { Head=null; Tail=null; Pointer=null; Length=0; } public void reset() /*链表复位,使第一个结点成为当前结点*/ { Pointer=null; } public boolean isEmpty() /*判断链表是否为空*/ { return(Length==0); } public boolean isEnd() /*判断当前结点是否为最后一个结点*/ { if(Length==0) throw new java.lang.NullPointerException(); else if(Length==1) return true; else return(cursor()==Tail); } public Object nextNode() /*返回当前结点的下一个结点的值,并使其成为当前结点*/ { if(Length==1) throw new java.util.NoSuchElementException(); else if(Length==0) throw new java.lang.NullPointerException(); else { Node temp=cursor(); Pointer=temp; if(temp!=Tail) return(temp.next.data); else throw new java.util.NoSuchElementException(); } } public Object currentNode() /*返回当前结点的值*/ { Node temp=cursor(); return temp.data; } public void insert(Object d) /*在当前结点前插入一个结点,并使其成为当前结点*/ { Node e=new Node(d); if(Length==0) { Tail=e; Head=e; } else { Node temp=cursor(); e.next=temp; if(Pointer==null) Head=e; else Pointer.next=e; } Length++; } public int size() /*返回链表的大小*/ { return (Length); } public Object remove() /*将当前结点移出链表,下一个结点成为当前结点,如果移出的结点是最后一个结点,则第一个结点成为当前结点*/ { Object temp; if(Length==0) throw new java.util.NoSuchElementException(); else if(Length==1) { temp=Head.data; deleteAll(); } else { Node cur=cursor(); temp=cur.data; if(cur==Head) Head=cur.next; else if(cur==Tail) { Pointer.next=null; Tail=Pointer; reset(); } else Pointer.next=cur.next; Length--; } return temp; } private Node cursor() /*返回当前结点的指针*/ { if(Head==null) throw new java.lang.NullPointerException(); else if(Pointer==null) return Head; else return Pointer.next; } public static void main(String[] args) /*链表的简单应用举例*/ { List a=new List (); for(int i=1;i<=10;i++) a.insert(new Integer(i)); System.out.println(a.currentNode()); while(!a.isEnd()) System.out.println(a.nextNode()); a.reset(); while(!a.isEnd()) { a.remove(); } a.remove(); a.reset(); if(a.isEmpty()) System.out.println("There is no Node in List \n"); System.in.println("You can press return to quit\n"); try { System.in.read(); //确保用户看清程序运行结果 } catch(IOException e) {} } } class Node /*构成链表的结点定义*/ { Object data; Node next; Node(Object d) { data=d; next=null; } } 读者还可以根据实际需要定义新的方法来对链表进行操作。双向链表可以用类似的方法实现只是结点的类增加了一个指向前趋结点的指针。 可以用这样的代码来实现: class Node { Object data; Node next; Node previous; Node(Object d) { data=d; next=null; previous=null; } } 当然,双向链表基本操作的实现略有不同。链表和双向链表的实现方法,也可以用在堆栈和队列的实现中,这里就不再多写了,有兴趣的读者可以将List类的代码稍加改动即可。

Q6:java 链表

class Node { Object data; Node next;//申明类Node类的对象叫Next public Node(Object data) { //类Node的构造函数 setData(data); } public void setData(Object data) { this.data = data; } public Object getData() { return data; } } class Link { Node head;//申明一个Node类的一个对象 head int size = 0; public void add(Object data) { Node n = new Node(data); //调用Node类的构造函数链表是一种重要的数据结构,在程序设计中占有很重要的地位。C语言和C++语言中是用指针来实现链表结构的,由于Java语言不提供指针,所以有人认为在Java语言中不能实现链表,其实不然,Java语言比C和C++更容易实现链表结构。Java语言中的对象引用实际上是一个指针(本文中的指针均为概念上的意义,而非语言提供的数据类型),所以我们可以编写这样的类来实现链表中的结点。 class Node { Object data; Node next;//指向下一个结点 } 将数据域定义成Object类是因为Object类是广义超类,任何类对象都可以给其赋值,增加了代码的通用性。为了使链表可以被访问还需要定义一个表头,表头必须包含指向第一个结点的指针和指向当前结点的指针。为了便于在链表尾部增加结点,还可以增加一指向链表尾部的指针,另外还可以用一个域来表示链表的大小,当调用者想得到链表的大小时,不必遍历整个链表。下图是这种链表的示意图: 链表的数据结构 我们可以用类List来实现链表结构,用变量Head、Tail、Length、Pointer来实现表头。存储当前结点的指针时有一定的技巧, Pointer并非存储指向当前结点的指针,而是存储指向它的前趋结点的指针,当其值为null时表示当前结点是第一个结点。那么为什么要这样做呢?这是因为当删除当前结点后仍需保证剩下的结点构成链表,如果Pointer指向当前结点,则会给操作带来很大困难。那么如何得到当前结点呢,我们定义了一个方法cursor(),返回值是指向当前结点的指针。类List还定义了一些方法来实现对链表的基本操作,通过运用这些基本操作我们可以对链表进行各种操作。例如reset()方法使第一个结点成为当前结点。insert(Object d)方法在当前结点前插入一个结点,并使其成为当前结点。remove()方法删除当前结点同时返回其内容,并使其后继结点成为当前结点,如果删除的是最 后一个结点,则第一个结点变为当前结点。 链表类List的源代码如下: import java.io.*; public class List { /*用变量来实现表头*/ private Node Head=null; private Node Tail=null; private Node Pointer=null; private int Length=0; public void deleteAll() /*清空整个链表*/ { Head=null; Tail=null; Pointer=null; Length=0; } public void reset() /*链表复位,使第一个结点成为当前结点*/ { Pointer=null; } public boolean isEmpty() /*判断链表是否为空*/ { return(Length==0); } public boolean isEnd() /*判断当前结点是否为最后一个结点*/ { if(Length==0) throw new java.lang.NullPointerException(); else if(Length==1) return true; else return(cursor()==Tail); } public Object nextNode() /*返回当前结点的下一个结点的值,并使其成为当前结点*/ { if(Length==1) throw new java.util.NoSuchElementException(); else if(Length==0) throw new java.lang.NullPointerException(); else { Node temp=cursor(); Pointer=temp; if(temp!=Tail) return(temp.next.data); else throw new java.util.NoSuchElementException(); } } public Object currentNode() /*返回当前结点的值*/ { Node temp=cursor(); return temp.data; } public void insert(Object d) /*在当前结点前插入一个结点,并使其成为当前结点*/ { Node e=new Node(d); if(Length==0) { Tail=e; Head=e; } else { Node temp=cursor(); e.next=temp; if(Pointer==null) Head=e; else Pointer.next=e; } Length++; } public int size() /*返回链表的大小*/ { return (Length); } public Object remove() /*将当前结点移出链表,下一个结点成为当前结点,如果移出的结点是最后一个结点,则第一个结点成为当前结点*/ { Object temp; if(Length==0) throw new java.util.NoSuchElementException(); else if(Length==1) { temp=Head.data; deleteAll(); } else { Node cur=cursor(); temp=cur.data; if(cur==Head) Head=cur.next; else if(cur==Tail) { Pointer.next=null; Tail=Pointer; reset(); } else Pointer.next=cur.next; Length--; } return temp; } private Node cursor() /*返回当前结点的指针*/ { if(Head==null) throw new java.lang.NullPointerException(); else if(Pointer==null) return Head; else return Pointer.next; } public static void main(String[] args) /*链表的简单应用举例*/ { List a=new List (); for(int i=1;i<=10;i++) a.insert(new Integer(i)); System.out.println(a.currentNode()); while(!a.isEnd()) System.out.println(a.nextNode()); a.reset(); while(!a.isEnd()) { a.remove(); } a.remove(); a.reset(); if(a.isEmpty()) System.out.println("There is no Node in List \n"); System.in.println("You can press return to quit\n"); try { System.in.read(); //确保用户看清程序运行结果 } catch(IOException e) {} } } class Node /*构成链表的结点定义*/ { Object data; Node next; Node(Object d) { data=d; next=null; } } 读者还可以根据实际需要定义新的方法来对链表进行操作。双向链表可以用类似的方法实现只是结点的类增加了一个指向前趋结点的指针。 可以用这样的代码来实现: class Node { Object data; Node next; Node previous; Node(Object d) { data=d; next=null; previous=null; } } 当然,双向链表基本操作的实现略有不同。链表和双向链表的实现方法,也可以用在堆栈和队列的实现中,这里就不再多写了,有兴趣的读者可以将List类的代码稍加改动即可。

相关文章