精华内容
下载资源
问答
  • 【单选题】材料HT200中“200”表示( )【单选题】能同时实现轴向固定于周向固定的是( )【单选题】滚动轴承基本代号为73220的轴承类型为( )【判断题】机械振动可以引起砂土液化吗【判断题】基本代号为6107、6207、6307...

    【简答题】任务三:定律应用

    【填空题】震动液化诱发因素的土质条件有哪些

    【判断题】地震要素中引起砂土液化的因素是地震波。

    【单选题】材料HT200中“200”表示( )

    【单选题】能同时实现轴向固定于周向固定的是( )

    【单选题】滚动轴承基本代号为73220的轴承类型为( )

    【判断题】机械振动可以引起砂土液化吗

    【判断题】基本代号为6107、6207、6307的滚动轴承的内径都是相同的。( )

    【判断题】按照外形不同,曲轴可以分为光轴和阶梯轴两种。

    【填空题】震动液化的排水条件有哪些?

    【单选题】合金钢20Cr2Ni4A中,元素铬的含量为( )

    【判断题】材料的屈服点越低,则允许的工作应力越高

    【判断题】滚动轴承常见的失效形式有疲劳剥落、磨损、塑性变形、保持架损坏等。( )

    【判断题】地震震级与烈度是一回事。

    【单选题】推力球轴承的类型代号为( )。

    【判断题】爆破可以引发砂土液化吗?

    【多选题】下列能对轴上零件实现周向固定的是( )、( )

    【单选题】滚动轴承基本代号62203的轴承内径为( )

    【判断题】滚动轴承7310B的公称接触角为15°。( )

    【论述题】针对你感兴趣的一种植物资源,给大家介绍一下! (100.0分)

    【单选题】滚动轴承基本代号中尺寸系列代号是由两位数字表示的,前者代表轴承的宽(高)度系列,后者代表轴承的( )系列。

    【多选题】下列能对轴上零件实现轴向固定的是( )、( )

    【名词解释】Linux Kernel

    【简答题】练习 (见图) : 求未知电流?

    【单选题】自行车的车轮轴属于( )

    【判断题】心轴用来支承转动零件,只受弯曲作用而不传递动力。

    【简答题】任务四:拓展应用 建立 KCL方程

    【单选题】( )是钢中的有益元素。

    【单选题】合金钢40CrNiMo中碳的质量分数(含碳量)为( )

    【单选题】材料QT400-18属于( )

    【其它】请提交课堂讨论报告

    【判断题】地震可以引起砂土液化吗?

    【单选题】转轴上被轴承支承的部位称为( )

    【单选题】材料QT400-18中“18”表示材料的最小伸长率为( )

    【判断题】根据轴所受的载荷不同,轴可以分为曲轴、直轴和挠性轴三类。

    【名词解释】ARM

    【简答题】任务二:定律+例题分析

    【判断题】地震波中横波比纵波传播速度快。

    【单选题】GCr15钢的平均含铬量为( )%

    【判断题】角接触球轴承的公称接触角越大,承受径向载荷的能力就越大。( )

    【单选题】粗砂的粒径是大于多少超过总质量的百分之50。

    【其它】上机操作题目 在虚拟机中安装Linux操作系统 建立一个用户,用户名为stu,用户密码为123456 以stu用户登录。进入用户主目录,显示当前的路径 复制文件/etc/passwd到用户stu的主目录,文件名称不变。 在stu用户的主目录下创建一个目录,名为one,文件拥有者可以读写,其他用户没有任何权限, 在用户主目录下用vi 新建文件myls,文件内容为:pwd; ls -al 。然后存盘退出。在命令提示符下输入./myls,看是否能正常运行。 打包并压缩/home/stu目录的命令,最终形成一个文件名为filename.tar.gz的文件。 在stu用户的主目录下创建一个目录,名为arm,将arm-linux-gcc4.4.3安装到此目录

    【判断题】在使用条件相同的条件下,类型代号越大,滚动轴承的承载能力越大。( )

    【单选题】滚动轴承基本代号为60308的轴承内径为( )

    【简答题】测量工作流程

    【简答题】卷瓶带主轴零件,如果是批量生产下列表面尺寸应该用什么测量器具检测呢? 外圆: Φ 30 0/-0.021, Φ 25 0/-0.021, Φ 15 0/-0.018 键槽宽度: 5 0/-0.036

    【单选题】制造小弹簧应选择下列哪种材料( )。

    【单选题】轴肩与轴环的作用是( )

    【单选题】滚动轴承62/28的轴承内径为( )

    【判断题】颗粒级配良好的细砂,在没有地下水的情况下遇到震动条件,是不会发生砂土液化的。

    展开全文
  • 电路板上的英文除了英文字母加数字表示元器件编号以外,还有一些信号的标注,比如VCC,VDD,GND之类的,我们经常可以在电路板上看到这样的英文,那么它们代表什么意思呢?下面请随我一起来解读一下。 在这之前,我们先...
  • 类图是静态的-它们显示出什么可以产生影响但不会告诉你什么时候产生影响 1、关联双向关联:C1-C2:指双方都知道对方的存在,都可以调用对方的公共属性和方法。在GOF的设计模式书上是这样描述的:虽然在分析阶段...
    转:
    类图Class diagram通过显示出系统的类以及这些类之间的关系来表示系统。类图是静态的-它们显示出什么可以产生影响但不会告诉你什么时候产生影响
    1、关联


    双向关联:
    C1-C2:指双方都知道对方的存在,都可以调用对方的公共属性和方法。

    在GOF的设计模式书上是这样描述的:虽然在分析阶段这种关系是适用的,但我们觉得它对于描述设计模式内的类关系来说显得太抽象了,因为在设计阶段关联关系必须被映射为对象引用或指针。对象引用本身就是有向的,更适合表达我们所讨论的那种关系。所以这种关系在设计的时候比较少用到,关联一般都是有向的。

    使用ROSE 生成的代码是这样的:
    class C1 
    ...{
    public:
        C2* theC2;

    };

    class C2 
    ...{
    public:
        C1* theC1;

    };

    双向关联在代码的表现为双方都拥有对方的一个指针,当然也可以是引用或者是值。





    单向关联:
    C3->C4:表示相识关系,指C3知道C4,C3可以调用C4的公共属性和方法。没有生命期的依赖。一般是表示为一种引用。

    生成代码如下:

    class C3 
    ...{
    public:
        C4* theC4;

    };

    class C4 
    ...{

    };

    单向关联的代码就表现为C3有C4的指针,而C4对C3一无所知。



    自身关联(反身关联):
    自己引用自己,带着一个自己的引用。

    代码如下:

    class C14 
    ...{
    public:
        C14* theC14;

    };

    就是在自己的内部有着一个自身的引用。

    2、聚合/组合

    当类之间有整体-部分关系的时候,我们就可以使用组合或者聚合。



    聚合:表示C9聚合C10,但是C10可以离开C9而独立存在(独立存在的意思是在某个应用的问题域中这个类的存在有意义。这句话怎么解,请看下面组合里的解释)。

    代码如下:

    class C9 
    ...{
    public:
        C10 theC10;

    };

    class C10 
    ...{

    };

     



    组合(也有人称为包容):一般是实心菱形加实线箭头表示,如上图所示,表示的是C8被C7包容,而且C8不能离开C7而独立存在。但这是视问题域而定的,例如在关心汽车的领域里,轮胎是一定要组合在汽车类中的,因为它离开了汽车就没有意义了。但是在卖轮胎的店铺业务里,就算轮胎离开了汽车,它也是有意义的,这就可以用聚合了。在《敏捷开发》中还说到,A组合B,则A需要知道B的生存周期,即可能A负责生成或者释放B,或者A通过某种途径知道B的生成和释放。

    他们的代码如下:

    class C7 
    ...{
    public:
        C8 theC8;

    };

    class C8 
    ...{
    };

    可以看到,代码和聚合是一样的。具体如何区别,可能就只能用语义来区分了。

    3、依赖



    依赖:
    指C5可能要用到C6的一些方法,也可以这样说,要完成C5里的所有功能,一定要有C6的方法协助才行。C5依赖于C6的定义,一般是在C5类的头文件中包含了C6的头文件。ROSE对依赖关系不产生属性。

    注意,要避免双向依赖。一般来说,不应该存在双向依赖。

    ROSE生成的代码如下:

    // C5.h
    #include "C6.h"

    class C5 
    ...{

    };

    // C6.h
    #include "C5.h"

    class C6
    ...{

    };

    虽然ROSE不生成属性,但在形式上一般是A中的某个方法把B的对象作为参数使用(假设A依赖于B)。如下:

    #include "B.h"
    class A
    ...{
              void Func(B &b);
    }

    那依赖和聚合\组合、关联等有什么不同呢?

    关联是类之间的一种关系,例如老师教学生,老公和老婆,水壶装水等就是一种关系。这种关系是非常明显的,在问题领域中通过分析直接就能得出。

    依赖是一种弱关联,只要一个类用到另一个类,但是和另一个类的关系不是太明显的时候(可以说是“uses”了那个类),就可以把这种关系看成是依赖,依赖也可说是一种偶然的关系,而不是必然的关系,就是“我在某个方法中偶然用到了它,但在现实中我和它并没多大关系”。例如我和锤子,我和锤子本来是没关系的,但在有一次要钉钉子的时候,我用到了它,这就是一种依赖,依赖锤子完成钉钉子这件事情。

    组合是一种整体-部分的关系,在问题域中这种关系很明显,直接分析就可以得出的。例如轮胎是车的一部分,树叶是树的一部分,手脚是身体的一部分这种的关系,非常明显的整体-部分关系。

    上述的几种关系(关联、聚合/组合、依赖)在代码中可能以指针、引用、值等的方式在另一个类中出现,不拘于形式,但在逻辑上他们就有以上的区别。

    这里还要说明一下,所谓的这些关系只是在某个问题域才有效,离开了这个问题域,可能这些关系就不成立了,例如可能在某个问题域中,我是一个木匠,需要拿着锤子去干活,可能整个问题的描述就是我拿着锤子怎么钉桌子,钉椅子,钉柜子;既然整个问题就是描述这个,我和锤子就不仅是偶然的依赖关系了,我和锤子的关系变得非常的紧密,可能就上升为组合关系(让我突然想起武侠小说的剑不离身,剑亡人亡...)。这个例子可能有点荒谬,但也是为了说明一个道理,就是关系和类一样,它们都是在一个问题领域中才成立的,离开了这个问题域,他们可能就不复存在了。


    4、泛化(继承)



    泛化关系:如果两个类存在泛化的关系时就使用,例如父和子,动物和老虎,植物和花等。
    ROSE生成的代码很简单,如下:

    #include "C11.h"

    class C12 : public C11
    ...{
    };


    5、这里顺便提一下模板



    上面的图对应的代码如下:

    template<int>
    class C13 
    ...{
    };

    这里再说一下重复度,其实看完了上面的描述之后,我们应该清楚了各个关系间的关系以及具体对应到代码是怎么样的,所谓的重复度,也只不过是上面的扩展,例如A和B有着“1对多”的重复度,那在A中就有一个列表,保存着B对象的N个引用,就是这样而已。

    好了,到这里,已经把上面的类图关系说完了,希望你能有所收获了,我也费了不少工夫啊(画图、生成代码、截图、写到BLOG上,唉,一头大汗)。不过如果能让你彻底理解UML类图的这些关系,也值得了。:)


    **************************************************************************************

    在UML建模中,对类图上出现元素的理解是至关重要的。开发者必须理解如何将类图上出现的元素转换到Java中。以java为代表结合网上的一些实例,下面是个人一些基本收集与总结:
     
    基本元素符号:
     
    1. 类(Classes)
    类包含3个组成部分。第一个是Java中定义的类名。第二个是属性(attributes)。第三个是该类提供的方法。
    属性和操作之前可附加一个可见性修饰符。加号(+)表示具有公共可见性。减号(-)表示私有可见性。#号表示受保护的可见性。省略这些修饰符表示具有package(包)级别的可见性。如果属性或操作具有下划线,表明它是静态的。在操作中,可同时列出它接受的参数,以及返回类型,如下图所示:

     
      2. 包(Package)
    包是一种常规用途的组合机制。UML中的一个包直接对应于Java中的一个包。在Java中,一个包可能含有其他包、类或者同时含有这两者。进行建模时,你通常拥有逻辑性的包,它主要用于对你的模型进行组织。你还会拥有物理性的包,它直接转换成系统中的Java包。每个包的名称对这个包进行了惟一性的标识。

      3. 接口(Interface)
    接口是一系列操作的集合,它指定了一个类所提供的服务。它直接对应于Java中的一个接口类型。接口既可用下面的那个图标来表示(上面一个圆圈符号,圆圈符号下面是接口名,中间是直线,直线下面是方法名),也可由附加了<<interface>>的一个标准类来表示。通常,根据接口在类图上的样子,就能知道与其他类的关系。

    关 系:
     
    1. 依赖(Dependency)
    实体之间一个“使用”关系暗示一个实体的规范发生变化后,可能影响依赖于它的其他实例。更具体地说,它可转换为对不在实例作用域内的一个类或对象的任何类型的引用。其中包括一个局部变量,对通过方法调用而获得的一个对象的引用(如下例所示),或者对一个类的静态方法的引用(同时不存在那个类的一个实例)。也可利用“依赖”来表示包和包之间的关系。由于包中含有类,所以你可根据那些包中的各个类之间的关系,表示出包和包的关系。例如:动物与氧气

      2. 关联(Association)
    实体之间的一个结构化关系表明对象是相互连接的。箭头是可选的,它用于指定导航能力。如果没有箭头,暗示是一种双向的导航能力。在Java中,关联转换为一个实例作用域的变量,就像图E的“Java”区域所展示的代码那样。可为一个关联附加其他修饰符。多重性(Multiplicity)修饰符暗示着实例之间的关系。在示范代码中,Employee可以有0个或更多的TimeCard对象。但是,每个TimeCard只从属于单独一个Employee。例如:燕子与气候 

     
     
    3. 聚合(Aggregation)
    聚合是关联的一种形式,代表两个类之间的整体/局部关系。聚合暗示着整体在概念上处于比局部更高的一个级别,而关联暗示两个类在概念上位于相同的级别。聚合也转换成Java中的一个实例作用域变量。
    关联和聚合的区别纯粹是概念上的,而且严格反映在语义上。聚合还暗示着实例图中不存在回路。换言之,只能是一种单向关系。例如:公司和员工 

      4. 合成(Composition)
    合成是聚合的一种特殊形式,暗示“局部”在“整体”内部的生存期职责。合成也是非共享的。所以,虽然局部不一定要随整体的销毁而被销毁,但整体要么负责保持局部的存活状态,要么负责将其销毁。
    局部不可与其他整体共享。但是,整体可将所有权转交给另一个对象,后者随即将承担生存期职责。Employee和TimeCard的关系或许更适合表示成“合成”,而不是表示成“关联”。人与手 

      5. 泛化(Generalization)
    泛化表示一个更泛化的元素和一个更具体的元素之间的关系。泛化是用于对继承进行建模的UML元素。在Java中,用extends关键字来直接表示这种关系。(继承和泛化是反过来的)

     
      6. 实现(Realization)
    实例关系指定两个实体之间的一个合同。换言之,一个实体定义一个合同,而另一个实体保证履行该合同。对Java应用程序进行建模时,实现关系可直接用implements关键字来表示。





    . 基数:连线两端的数字表明这一端的类可以有几个实例,比如:一个鸟应该有两只翅膀。如果一个类可能有无数个实例,则就用‘n’来表示。关联、聚合、组合是有基数的。  
    展开全文
  • 盛年不重来,一日难再晨。及时宜自勉,岁月不待人。...学习了单链表,那么双向循环链表的意思就是一个结点有两个指针域,分别指向直接前驱结点和直接后继结点,并且尾结点指向头结点,这样的好处是什么呢? ...

    盛年不重来,一日难再晨。及时宜自勉,岁月不待人。

                                                                                          ——陶渊明

    目录

    一、前言

    二、双向循环链表图示

    三、双链表的存储结构

    四、常用操作的实现

    1.头插法建立双向循环链      图示   代码      2.尾插法建立双向循环链表    图示    代码                                       3.查找结点     

    4.获取链表长度                                           5.删除第i个结点     图示    代码       6.在第i个位置之前插入新结点    图示    代码

    7.输出链表                                                  8.修改第i个结点的值                       9.销毁链表                               10.清空链表

    五、源代码

    六、总结


     

    一、前言

    学习了单链表,我们发现每个结点只能找到其后继结点,而不能找到前驱结点,我们可以思考能否再加一个指针域,使其能够访问其前驱结点,这就是双链表的由来。因此双向循环链表的意思就是一个结点有两个指针域,分别指向直接前驱结点和直接后继结点,并且尾结点指向头结点,这样的好处是什么呢?

    好处就是可以直接访问某个结点的前驱结点,并且由任意一个结点出发均能找到表中所有结点。这在单链表中是不能实现的。应用在双向查询的场合,但双向循环链表的缺点就是占用内存大,而且操作稍微复杂。

    二、双向循环链表图示

    双向循环链表图示

    三、双链表的存储结构

    typedef struct DuLNode{
    	int            data;
    	struct DuLNode * prior;//前驱结点 
    	struct DuLNode * next; //后继结点 
    }DuLNode,* DuLinkList;
    
    /*  最后一句的等同于下面代码,中括号是我自己加上的,只是提示把他们看作是一个整体
     
    typedef  {struct  DuLNode   }  DuLNode;      // struct  DuLNode 的别名是 DuLNode
     
    typedef  {struct  DuLNode * }  DuLinkList;   // struct  DuLNode *  的别名是 DuLinkList
    
    */
    

    四、常用操作的实现

    1.头插法建立双向循环链表

    图示

    头插法建立双向循环链表

    代码

    
     //1.头插法建立线性表 
     Status create_headLinked_List(DuLinkList & L,int n) 
     //逆序输入n个元素的值,建立带表头结点双向循环链表L 
     {
     	DuLinkList head = (DuLinkList)malloc(sizeof(DuLNode));//头结点的存储地址 
     	if(NULL == head) return ERROR;                        //分配空间失败 
     	L = head;                                             //头指针L存储头结点P的地址,即头指针指向头结点 
     	L->data = 0; 					      //用头结点统计元素个数,刚开始为0个
    	L->prior = L;                                	      //链表为空,头结点prior指向自己 
     	L->next  = L;                             	      //链表为空,头结点next指向自己  
     							      //由此得出链表为空条件: L->next == L->prior == L 
     	for(int i = 0;i<n;i++)
    	 {
     		DuLinkList List_Node = (DuLinkList)malloc(sizeof(DuLNode));
     		if(NULL == List_Node) return ERROR;
     		scanf("%d",&List_Node->data);
     		L->data++;  
    		List_Node->prior  = head;                         
     		List_Node->next   = head->next;
    		head->next->prior = List_Node;                //头插法,即链表中的元素顺序与输入相反 
     		head->next = List_Node;
    	 } 
    	 return OK;
     }
     

    2.尾插法建立双向循环链表

    图示

      

    代码

    //2.尾插法创建带头结点的链表 
     Status tail_create_heahLinked_List(DuLinkList & L,int n) 
     {
     	DuLinkList head = (DuLinkList)malloc(sizeof(DuLNode));//头结点的存储地址 
     	if(NULL == head) return ERROR;                       
            L = head;                                             //头指针L存储头结点P的地址,即头指针指向头结点 
     	L->data = 0; 					      //用头结点统计元素个数,刚开始为0个
    	L->prior = L;                                		  
     	L->next  = L;                             		      
    	DuLinkList List_Node = NULL;                               
     	for(int i = 0;i<n;i++)
    	 {
     		List_Node = (DuLinkList)malloc(sizeof(DuLNode));
     		if(NULL == List_Node) return ERROR;
     		scanf("%d",&List_Node->data);
     		L->data++;  
    		List_Node->prior  = head->prior;
    		List_Node->next   = head;               //每插入一个元素,头结点统计链表元素个数加一 
     		head->prior->next = List_Node;          //尾插法,即链表中的元素顺序与输入相同 
     		head->prior = List_Node;
    	 } 
    	 return OK;
     }

    3.查找结点

     

    //3.查找某一个数据是否在链表中,如果没有,返回false,否则返回该结点的位序
     
     Status  getDuLNodeIndex(DuLinkList L,int number)
     {
     	int i=1;
     	DuLinkList  temp =L->next;
     	while(temp != L ) 
    	 {
     		if(number == temp->data) return i;
     		temp = temp->next;
     		i++;
    	 }
    	 return FALSE;
     }

     

    4.获取链表长度

     //4.获取链表长度
     Status getLength(DuLinkList L)
     {
     	return L->data;
     } 

     

    5.删除第i个结点

    图示

    代码

    //5.删除某个位置节点 (从1开始) 
     
     Status  deleteDuLNode(DuLinkList L ,int i,int & e)       //用e保存删除的节点 
     {
     	int j=1;
     	if(L->next == L && L->prior ==L )  return ERROR;  //表为空 
     	if(j > i || i>L->data)  return ERROR;             //说明位置不合理,直接返回 
     	DuLinkList temp = L;
    	while(j<=i)
    	{
    		temp = temp->next;
    		j++;
    	} 
    	e = temp->data; 
            temp->next->prior = temp->prior;
    	temp->prior->next = temp->next; 
    	free(temp);
    	L->data--;
    	return OK;
     } 
     

    6.在第i个位置之前插入新结点

    图示

    代码

    //6.在第i个位置之前插入新结点
    Status  insertDuLNode(DuLinkList L ,int i,int value)
    {
    	int j=1;
    	if( j > i || i>L->data + 1 )   return ERROR;//允许在最后一个元素之后插入元素 
    	DuLinkList temp = L;
    	DuLinkList newDuLNode = (DuLinkList)malloc(sizeof(DuLNode));
    	while(j<i)
    	{
    		temp = temp->next;
    		j++;
    	}
    	newDuLNode->data  = value;
    	newDuLNode->next  = temp->next;
    	newDuLNode->prior = temp;
    	temp->next->prior = newDuLNode;
    	temp->next = newDuLNode;
    	L->data++;
    	return OK;
    } 

    7.输出链表

    //7.输出带头结点链表中的元素 
     void headlinked_List_Traverse(DuLinkList  L)
     {
     	
        printf("该链表的元素个数为:%d \n",L->data);
    	DuLinkList p = L->next;    
     	while(p != L)
    	{    
     	    printf(" %d ",p->data);	
    		p = p->next;	    	
    	}
     	
    }

     

    8.修改第i个结点的值

    //8.修改第i个结点的值
    
    Status  updateDuLNode(DuLinkList L,int i,int value)
    {
    	int j=1;
     	if(L->next == L && L->prior ==L )  return ERROR;//表为空 
     	if(j > i || i>L->data)  return ERROR;           //说明位置不合理,直接返回 
    	DuLinkList temp = L;
    	while(j<=i )
    	{
    		temp = temp->next;
    		j++;
    	}  
            temp->data = value; 
    	return OK;
    } 

    9.销毁链表

    //销毁链表,包括头结点的所有结点全部释放	 
    Status destroy_headlinked_list(DuLinkList & L)	
    {
    	L->data = 0; 
    	DuLinkList p = NULL;
    	while(L)
    	{   
    	    p = L->next;
    	    free(L);
    	    L = p;			    	
    	} 
            L = NULL;
     	return OK;
    } 

     

    10.清空链表

    Status clear_headlinked_list(DuLinkList  L)	
    {
    	L->data = 0; 
    	DuLinkList p,q;
    	p = q = L->next;
    	while(p != L)
    	{   
    	    q = p->next;
    	    free(p);
    	    p = q;			    	
    	} 
    	L->next = L->prior = L;
     	return OK;
     
    }  

     

    五、源代码

    #include<cstdio>
    #include<cstdlib>
    #include<malloc.h>
    #include<cstring>
    #include<conio.h>
    //函数结果状态代码 
    #define TRUE  1
    #define FALSE 0
    #define OK    1
    #define ERROR 0 
    
    typedef int Status;  //int 的别名,其值是函数结果状态代码 
    
    typedef struct DuLNode{
    	int            data;
    	struct DuLNode * prior;//前一个结点 
    	struct DuLNode * next; //后一个结点 
    }DuLNode,* DuLinkList;
    
    /*  最后一句的等同于下面代码,中括号是我自己加上的,只是提示把他们看作是一个整体
     
    typedef  {struct  DuLNode   }  DuLNode;      // struct  DuLNode 的别名是 DuLNode
     
    typedef  {struct  DuLNode * }  DuLinkList;   // struct  DuLNode *  的别名是 DuLinkList
    
    */
    
    
     //1.建立线性表 
     Status create_headLinked_List(DuLinkList & L,int n) 
     //逆序输入n个元素的值,建立带表头结点双向循环链表L 
     {
     	DuLinkList head = (DuLinkList)malloc(sizeof(DuLNode));//头结点的存储地址 
     	if(NULL == head) return ERROR;                        //分配空间失败 
     	L = head;                                       	  //头指针L存储头结点P的地址,即头指针指向头结点 
     	L->data = 0; 										  //用头结点统计元素个数,刚开始为0个
    	L->prior = L;                                		  //链表为空,头结点prior指向自己 
     	L->next  = L;                             		      //链表为空,头结点next指向自己  
     													      //由此得出链表为空条件: L->next == L->prior == L 
     	
    	head->next = head;									
     	head->prior = head;
    	 for(int i = 0;i<n;i++)
    	 {
     		DuLinkList List_Node = (DuLinkList)malloc(sizeof(DuLNode));
     		if(NULL == List_Node) return ERROR;
     		scanf("%d",&List_Node->data);
     		L->data++;  
    		List_Node->prior  = head;                         
     		List_Node->next   = head->next;
    		head->next->prior = List_Node;                    //头插法,即链表中的元素顺序与输入相反 
     		head->next = List_Node;
    	 } 
    	 return OK;
     }
     
     //2.尾插法创建带头结点的链表 
     Status tail_create_heahLinked_List(DuLinkList & L,int n) 
     {
     	DuLinkList head = (DuLinkList)malloc(sizeof(DuLNode));//头结点的存储地址 
     	if(NULL == head) return ERROR;                       
        L = head;                                       	  //头指针L存储头结点P的地址,即头指针指向头结点 
     	L->data = 0; 										  //用头结点统计元素个数,刚开始为0个
    	L->prior = L;                                		  
     	L->next  = L;                             		      
    	DuLinkList List_Node = NULL;                               
     	for(int i = 0;i<n;i++)
    	 {
     		List_Node = (DuLinkList)malloc(sizeof(DuLNode));
     		if(NULL == List_Node) return ERROR;
     		scanf("%d",&List_Node->data);
     		L->data++;  
    		List_Node->prior  = head->prior;
    		List_Node->next   = head;               //每插入一个元素,头结点统计链表元素个数加一 
     		head->prior->next = List_Node;               //尾插法,即链表中的元素顺序与输入相同 
     		head->prior = List_Node;
    	 } 
    	 return OK;
     }
     
     
     //3.查找某一个数据是否在链表中,如果没有,返回false,否则返回该结点的位序
     
     Status  getDuLNodeIndex(DuLinkList L,int number)
     {
     	int i=1;
     	DuLinkList  temp =L->next;
     	while(temp != L ) 
    	 {
     		if(number == temp->data) return i;
     		temp = temp->next;
     		i++;
    	 }
    	 return FALSE;
     }
     
     //4.获取链表长度
     Status getLength(DuLinkList L)
     {
     	return L->data;
     } 
     
     //5.删除某个位置节点 (从1开始) 
     
     Status  deleteDuLNode(DuLinkList L ,int i,int & e)//用e保存删除的节点 
     {
     	int j=1;
     	if(L->next == L && L->prior ==L )  return ERROR;//表为空 
     	if(j > i || i>L->data)  return ERROR;//说明位置不合理,直接返回 
     	DuLinkList temp = L;
    	while(j<=i)
    	{
    		temp = temp->next;
    		j++;
    	} 
    	e = temp->data; 
        temp->next->prior = temp->prior;
    	temp->prior->next = temp->next; 
    	free(temp);
    	L->data--;
    	return OK;
     } 
     
    
      
    //6.在第i个位置之前插入新结点
    Status  insertDuLNode(DuLinkList L ,int i,int value)
    {
    	int j=1;
    	if( j > i || i>L->data + 1 )   return ERROR;//允许在最后一个元素之后插入元素 
    	DuLinkList temp = L;
    	DuLinkList newDuLNode = (DuLinkList)malloc(sizeof(DuLNode));
    	while(j<i)
    	{
    		temp = temp->next;
    		j++;
    	}
    	newDuLNode->data  = value;
    	newDuLNode->next  = temp->next;
    	newDuLNode->prior = temp;
    	temp->next->prior = newDuLNode;
    	temp->next = newDuLNode;
    	L->data++;
    	return OK;
    } 
    
    
    
     //7.输出带头结点链表中的元素 
     void headlinked_List_Traverse(DuLinkList  L)
     {
     	
        printf("该链表的元素个数为:%d \n",L->data);
    	DuLinkList p = L->next;    
     	while(p != L)
    	{    
     	    printf(" %d ",p->data);	
    		p = p->next;	    	
    	}
     	
    }
    
    //8.修改第i个结点的值
    
    Status  updateDuLNode(DuLinkList L,int i,int value)
    {
    	int j=1;
     	if(L->next == L && L->prior ==L )  return ERROR;//表为空 
     	if(j > i || i>L->data)  return ERROR;//说明位置不合理,直接返回 
    	DuLinkList temp = L;
    	while(j<=i )
    	{
    		temp = temp->next;
    		j++;
    	}  
        temp->data = value; //结点
    	return OK;
    } 
    
    //输出不带头结点链表中的元素 
     void linkedListTraverse(DuLinkList  L)
     {
    	DuLinkList p = L;    
     	while(p)
    	{    
     	    printf(" %d ",p->data);	
    		p = p->next;	    	
    	}
     	
    }
    
    /*清空链表跟销毁链表的区别 ... 销毁:是先销毁了链表的头,然后接着一个一个的把后面的销毁了,
    这样这个链表就不能再使用了,即把包括头的所有节点全部释放。 清空:是先保留了链表的头,
    然后把头后面的所有的都销毁,最后把头里指向下一个的指针设为空,
    这样就相当与清空了,但这个链表还在,还可以继续使用;即保留了头,后面的全部释放。*/
    //销毁链表,包括头结点的所有结点全部释放	 
    Status destroy_headlinked_list(DuLinkList & L)	
    {
    	L->data = 0; 
    	DuLinkList p = NULL;
    	while(p != L)
    	{   
    	    p = L->next;
    	    free(L);
    	    L = p;			    	
    	} 
        L = NULL;
     	return OK;
    }
    
    /*清空带头结点链表
      1.先保留链表的头结点
      2.然后把头结点后面的所有的都销毁
      3.最后把头结点里指向首元结点的指针设为空 */
    Status clear_headlinked_list(DuLinkList  L)	
    {
    	L->data = 0; 
    	DuLinkList p,q;
    	p = q = L->next;
    	while(p != L)
    	{   
    	    q = p->next;
    	    free(q);
    		p = q;			    	
    	} 
    	L->next = L->prior = L;
     	return OK;
     
    }  
    
    
    //销毁不带头结点的链表 
    
    Status destroy_linked_list(DuLinkList  L)
    {
    	DuLinkList p;
    	while(L)
    	{
    		p = L->next;
    		free(L);
    		L = p;
    	}
    	return OK;
    }
    
    int main(void)
    {
    	DuLinkList L;//头指针L 
    	int n = 0;
    	printf("请输入所要创建带头结点链表的元素个数:");
    	scanf("%d",&n);
    	
    	printf("\n\n请输入所要创建带头结点链表的元素数据:");
    	//if(create_headLinked_List( L, n) )     //头插法 
    	if( tail_create_heahLinked_List( L, n) ) //尾插法 
    		headlinked_List_Traverse(L);
    	int number=0;
    	printf("\n请输入查找的元素:");
    	scanf("%d",&number);
    	if(getDuLNodeIndex(L,number))	
        	printf("%d",getDuLNodeIndex(L, number));
        else printf("未找到! ");
        
        printf("\n该链表的长度为:%d",getLength(L));
    
        int i=1,value,e;
        printf("\n请输入删除结点的位置:");
    	scanf("%d",&i); 
        if(deleteDuLNode( L ,i,e))   
    		printf("\n删除结点%d成功\n",e);
        else    
    		printf("\n删除结点%d失败\n",e);
        
        headlinked_List_Traverse(L);
        printf("\n该链表的长度为:%d",getLength(L));
         
        printf("\n请输入插入结点的位置和数据:");
        scanf("%d %d",&i,&value); 
        insertDuLNode( L ,i, value);
        printf("\n该链表的长度为:%d",getLength(L));
        headlinked_List_Traverse(L);
        
        printf("\n请输入待修改结点的位置和数据:");
        scanf("%d %d",&i,&value); 	
    	updateDuLNode(L,i, value);
    	headlinked_List_Traverse(L);
    	
    	if(destroy_headlinked_list(L))
    		printf("\n销毁带头结点链表L成功!\n");
    	else printf("销毁失败!!\n"); 
    
    	
    	return 0;
    } 
      
    
    
     

    六、总结

     

    1.理解双向循环链表的关键就是理清链表的首尾关系,即临界点,另外就是要勤加练习双向思考,多实践

    2.每插入或者删除一个结点时,都要考虑前驱后继的关系

    3.双向循环链表可以做链表的逆序输出、双向查找等等,有着很多的优点,代价就是多了一个指针域

     

    展开全文
  • CLH同步队列是一个FIFO双向队列,AQS依赖它来完成同步状态的管理,当前线程如果获取同步状态失败时,AQS则会将当前线程已经等待状态等信息构造成一个节点(Node)并将其加入到CLH同步队列,同时会阻塞当前线程,当同步...

    CLH同步队列是一个FIFO双向队列,AQS依赖它来完成同步状态的管理,当前线程如果获取同步状态失败时,AQS则会将当前线程已经等待状态等信息构造成一个节点(Node)并将其加入到CLH同步队列,同时会阻塞当前线程,当同步状态释放时,会把首节点唤醒(公平锁),使其再次尝试获取同步状态。

    在CLH同步队列中,一个节点表示一个线程,它保存着线程的引用(thread)、状态(waitStatus)、前驱节点(prev)、后继节点(next),其定义如下:

    static final class Node {

    /** 共享 */

    static final Node SHARED = new Node();

    /** 独占 */

    static final Node EXCLUSIVE = null;

    /**

    * 因为超时或者中断,节点会被设置为取消状态,被取消的节点时不会参与到竞争中的,他会一直保持取消状态不会转变为其他状态;

    */

    static final int CANCELLED = 1;

    /**

    * 后继节点的线程处于等待状态,而当前节点的线程如果释放了同步状态或者被取消,将会通知后继节点,使后继节点的线程得以运行

    */

    static final int SIGNAL = -1;

    /**

    * 节点在等待队列中,节点线程等待在Condition上,当其他线程对Condition调用了signal()后,改节点将会从等待队列中转移到同步队列中,加入到同步状态的获取中

    */

    static final int CONDITION = -2;

    /**

    * 表示下一次共享式同步状态获取将会无条件地传播下去

    */

    static final int PROPAGATE = -3;

    /** 等待状态 */

    volatile int waitStatus;

    /** 前驱节点 */

    volatile Node prev;

    /** 后继节点 */

    volatile Node next;

    /** 获取同步状态的线程 */

    volatile Thread thread;

    Node nextWaiter;

    final boolean isShared() {

    return nextWaiter == SHARED;

    }

    final Node predecessor() throws NullPointerException {

    Node p = prev;

    if (p == null)

    throw new NullPointerException();

    else

    return p;

    }

    Node() {

    }

    Node(Thread thread, Node mode) {

    this.nextWaiter = mode;

    this.thread = thread;

    }

    Node(Thread thread, int waitStatus) {

    this.waitStatus = waitStatus;

    this.thread = thread;

    }

    }

    CLH同步队列结构图如下:

    0b83f852fb7cdae10e542e48f06df3c3.png

    入列

    学了数据结构的我们,CLH队列入列是再简单不过了,无非就是tail指向新节点、新节点的prev指向当前最后的节点,当前最后一个节点的next指向当前节点。代码我们可以看看addWaiter(Node node)方法:

    private Node addWaiter(Node mode) {

    //新建Node

    Node node = new Node(Thread.currentThread(), mode);

    //快速尝试添加尾节点

    Node pred = tail;

    if (pred != null) {

    node.prev = pred;

    //CAS设置尾节点

    if (compareAndSetTail(pred, node)) {

    pred.next = node;

    return node;

    }

    }

    //多次尝试

    enq(node);

    return node;

    }

    addWaiter(Node node)先通过快速尝试设置尾节点,如果失败,则调用enq(Node node)方法设置尾节点

    private Node enq(final Node node) {

    //多次尝试,直到成功为止

    for (;;) {

    Node t = tail;

    //tail不存在,设置为首节点

    if (t == null) {

    if (compareAndSetHead(new Node()))

    tail = head;

    } else {

    //设置为尾节点

    node.prev = t;

    if (compareAndSetTail(t, node)) {

    t.next = node;

    return t;

    }

    }

    }

    }

    在上面代码中,两个方法都是通过一个CAS方法compareAndSetTail(Node expect, Node update)来设置尾节点,该方法可以确保节点是线程安全添加的。在enq(Node node)方法中,AQS通过“死循环”的方式来保证节点可以正确添加,只有成功添加后,当前线程才会从该方法返回,否则会一直执行下去。

    过程图如下:

    9007dc09ad27cd6e4755977fb3bc0d8a.png

    出列

    CLH同步队列遵循FIFO,首节点的线程释放同步状态后,将会唤醒它的后继节点(next),而后继节点将会在获取同步状态成功时将自己设置为首节点,这个过程非常简单,head执行该节点并断开原首节点的next和当前节点的prev即可,注意在这个过程是不需要使用CAS来保证的,因为只有一个线程能够成功获取到同步状态。过程图如下:

    f4b277d4ada098cd74242ba88871468e.png

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家

    展开全文
  • 情景:vue双向绑定,这应该是多数讲vue优势脱口而出的名词,然后你就会接触到一个方法 Object.defineProperty(a,"b",{}) 这个方法该怎么用 ...参数怎么传,分别表示什么意思 第一个参数...
  • 什么是I帧,P帧,B帧

    万次阅读 多人点赞 2011-06-30 18:53:00
     P是向前搜索的意思。B是双向搜索。他们都是基于I帧来压缩数据。   I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面) P帧表示的是这一帧跟
  •  如:关系有单向和双向之分,但是在数据库中,单向关系和双向关系其实并没有什么区别,  这里的单双向指的是对象之间是否能够相互访问 铁律: 1、凡是双向关联,必设mappedBy  因为根本都没必要在2个表中都...
  • P是向前搜索的意思。B是双向搜索。他们都是基于I帧来压缩数据。 I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面) P帧表示的是这一帧跟之前的一个关键...

空空如也

空空如也

1 2 3 4
收藏数 70
精华内容 28
关键字:

双向表示什么意思