精华内容
下载资源
问答
  • 查找表的原理与结构查找表(look-up-table)简称为LUT,LUT本质上就是一个RAM。目前FPGA中多使用4输入的LUT,所以每一个LUT可以看成一个有 4位地址线的16x1的RAM。当用户通过原理图或HDL语言描述了一个逻辑电路...

    查找表的原理与结构:
          查找表(look-up-table)简称为LUT,LUT本质上就是一个RAM。目前FPGA中多使用4输入的LUT,所以每一个LUT可以看成一个有 4位地址线的16x1的RAM。当用户通过原理图或HDL语言描述了一个逻辑电路以后,PLD/FPGA开发软件会自动计算逻辑电路的所有可能的结果,并把结果事先写入RAM,这样,每输入一个信号进行逻辑运算就等于输入一个地址进行查表,找出地址对应的内容,然后输出即可。
    什么是竞争与冒险现象:
                在组合电路中,某一输入变量经过不同途径传输后,到达电路中某一汇合点的时间有先有后,这种现象称竞争;由于竞争而使电路输出发生瞬时错误的现象叫做冒险。(也就是由于竞争产生的毛刺叫做冒险)
    判断方法:
    代数法(如果布尔式中有相反的信号则可能产生
    竞争和冒险现象);
    卡诺图:有两个相切的卡诺圈并且相切处没有被其他卡诺圈包围,就有
    可能出现竞争冒险;
    实验法:示波器观测;
    解决方法:
    1:加滤波电路,消除毛刺的影响;
    2:加选通信号,避开毛刺;
    3:增加冗余项消除逻辑冒险。 

    展开全文
  • 数据结构 Hash(哈希

    万次阅读 多人点赞 2018-05-20 01:23:34
    什么是Hash 要想知道什么是哈希,那得先了解哈希函数 哈希函数 对比之前博客讨论的二叉排序树 二叉平衡树 红黑树 B B+树,它们的查找先从根节点进行查找,从节点取出数据或索引与查找值进行比较。那么...

    参考链接:数据结构(严蔚敏)

    一、什么是Hash表

    要想知道什么是哈希表,那得先了解哈希函数
    哈希函数

    对比之前博客讨论的二叉排序树 二叉平衡树 红黑树 B B+树,它们的查找都是先从根节点进行查找,从节点取出数据或索引与查找值进行比较。那么,有没有一种函数H,根据这个函数和查找关键字key,可以直接确定查找值所在位置,而不需要一个个比较。这样就**“预先知道”**key所在的位置,直接找到数据,提升效率。

    地址index=H(key)
    说白了,hash函数就是根据key计算出应该存储地址的位置,而哈希表是基于哈希函数建立的一种查找表

    二、哈希函数的构造方法

    根据前人经验,统计出如下几种常用hash函数的构造方法:
    直接定制法
    哈希函数为关键字的线性函数如 H(key)=a*key+b
    这种构造方法比较简便,均匀,但是有很大限制,仅限于地址大小=关键字集合的情况
    使用举例:
    假设需要统计中国人口的年龄分布,以10为最小单元。今年是2018年,那么10岁以内的分布在2008-2018,20岁以内的分布在1998-2008……假设2018代表2018-2008直接的数据,那么关键字应该是2018,2008,1998……
    那么可以构造哈希函数H(key)=(2018-key)/10=201-key/10
    那么hash表建立如下

    index key 年龄 人数(假设数据)
    0 2018 0-10 200W
    1 2008 10-20 250W
    2 1998 20-30 253W
    3 1988 30-40 300W
    ……

    数字分析法
    假设关键字集合中的每个关键字key都是由s位数字组成(k1,k2,,knk_1,k_2,……,k_n),分析key中的全体数据,并从中提取分布均匀的若干位或他们的组合构成全体

    使用举例
    我们知道身份证号是有规律的,现在我们要存储一个班级学生的身份证号码,假设这个班级的学生都出生在同一个地区,同一年,那么他们的身份证的前面数位都是相同的,那么我们可以截取后面不同的几位存储,假设有5位不同,那么就用这五位代表地址。
    H(key)=key%100000
    此种方法通常用于数字位数较长的情况,必须数字存在一定规律,其必须知道数字的分布情况,比如上面的例子,我们事先知道这个班级的学生出生在同一年,同一个地区。
    平方取中法
    如果关键字的每一位都有某些数字重复出现频率很高的现象,可以先求关键字的平方值,通过平方扩大差异,而后取中间数位作为最终存储地址。
    使用举例
    比如key=1234 1234^2=1522756 取227作hash地址
    比如key=4321 4321^2=18671041 取671作hash地址
    这种方法适合事先不知道数据并且数据长度较小的情况
    折叠法
    如果数字的位数很多,可以将数字分割为几个部分,取他们的叠加和作为hash地址
    使用举例
    比如key=123 456 789
    我们可以存储在61524,取末三位,存在524的位置
    该方法适用于数字位数较多且事先不知道数据分布的情况
    除留余数法用的较多
    H(key)=key MOD p (p<=m m为表长)
    很明显,如何选取p是个关键问题。

    使用举例
    比如我们存储3 6 9,那么p就不能取3
    因为 3 MOD 3 == 6 MOD 3 == 9 MOD 3
    p应为不大于m的质数或是不含20以下的质因子的合数,这样可以减少地址的重复(冲突)

    比如key = 7,39,18,24,33,21时取表长m为9 p为7 那么存储如下

    index 0 1 2 3 4 5 6 7 8
    key 7 21(冲突后移) 24 *39* 18(冲突后移) 33冲突后移)
    **随机数法** H(key) =Random(key) 取关键字的随机函数值为它的散列地址

    hash函数设计的考虑因素

    1.计算散列地址所需要的时间(即hash函数本身不要太复杂)
    2.关键字的长度
    3.表长
    4.关键字分布是否均匀,是否有规律可循
    5.设计的hash函数在满足以上条件的情况下尽量减少冲突

    三、哈希冲突

    即不同key值产生相同的地址,H(key1)=H(key2)
    比如我们上面说的存储3 6 9,p取3是
    3 MOD 3 == 6 MOD 3 == 9 MOD 3
    此时3 6 9都发生了hash冲突

    哈希冲突的解决方案

    不管hash函数设计的如何巧妙,总会有特殊的key导致hash冲突,特别是对动态查找表来说。
    hash函数解决冲突的方法有以下几个常用的方法
    1.开放定制法
    2.链地址法
    3.公共溢出区法
    建立一个特殊存储空间,专门存放冲突的数据。此种方法适用于数据和冲突较少的情况。
    4.再散列法
    准备若干个hash函数,如果使用第一个hash函数发生了冲突,就使用第二个hash函数,第二个也冲突,使用第三个……
    重点了解一下开放定制法和链地址法

    开放定制法

    首先有一个H(key)的哈希函数
    如果H(key1)=H(keyi)
    那么keyi存储位置Hi=(H(key)+di)MODmH_i=(H(key)+d_i)MOD mm为表长
    did_i有三种取法
    1)线性探测再散列
    di=cid_i=c*i
    2)平方探测再散列
    di=12,12,22,22d_i=1^2,-1^2,2^2,-2^2……
    3)随机探测在散列(双探测再散列)
    did_i是一组伪随机数列
    注意
    增量di应该具有以下特点(完备性):产生的Hi(地址)均不相同,且所产生的s(m-1)个Hi能覆盖hash表中的所有地址

    • 平方探测时表长m必须为4j+3的质数(平方探测表长有限制)
    • 随机探测时m和di没有公因子(随机探测di有限制)
      三种开放定址法解决冲突方案的例子

    废话不多说,上例子就明白了
    有一组数据
    19 01 23 14 55 68 11 86 37要存储在表长11的数组中,其中H(key)=key MOD 11
    那么按照上面三种解决冲突的方法,存储过程如下:
    (表格解释:从前向后插入数据,如果插入位置已经占用,发生冲突,冲突的另起一行,计算地址,直到地址可用,后面冲突的继续向下另起一行。最终结果取最上面的数据(因为是最“占座”的数据))
    线性探测再散列
    我们取di=1,即冲突后存储在冲突后一个位置,如果仍然冲突继续向后

    index 0 1 2 3 4 5 6 7 8 9 10
    key 55 1 14 19 86
    23冲突 23
    68冲突 68冲突 68
    11冲突 11冲突 11冲突 11冲突 11冲突 11
    37冲突 37冲突 37
    最终存储结果 55 1 23 14 68 11 37 19 86
    **平方探测再散列**
    index 0 1 2 3 4 5 6 7 8 9 10
    key 55 1 14 37 19 86
    23冲突 H(23)+1
    H(68)-1冲突 68冲突 H(68)+1冲突 H(68)+4
    11冲突 H(11)+1冲突 H(11)-1
    最终存储结果 55 1 23 14 37 68 19 86 11
    **随机探测在散列(双探测再散列)** 发生冲突后 H(key)‘=(H(key)+di)MOD m 在该例子中 H(key)=key MOD 11 我们取di=key MOD 10 +1 则有如下结果:
    index 0 1 2 3 4 5 6 7 8 9 10
    key 55 1 68 14 19 86
    23冲突 H(23)+3+1
    11冲突 H(11)+1+1冲突 H(11)+1+1+1+1
    (H(37)+8)模11冲突 37冲突 (H(37)+8+8+8)模11 (H(37)+8+8)模11冲突
    最终存储结果 55 1 68 14 23 11 37 19 86

    链地址法

    产生hash冲突后在存储数据后面加一个指针,指向后面冲突的数据
    上面的例子,用链地址法则是下面这样:

    这里写图片描述
    四、hash表的查找

    查找过程和造表过程一致,假设采用开放定址法处理冲突,则查找过程为:
    对于给定的key,计算hash地址index = H(key)
    如果数组arr【index】的值为空 则查找不成功
    如果数组arr【index】== key 则查找成功
    否则 使用冲突解决方法求下一个地址,直到arr【index】== key或者 arr【index】==null

    hash表的查找效率

    决定hash表查找的ASL因素:
    1)选用的hash函数
    2)选用的处理冲突的方法
    3)hash表的饱和度,装载因子 α=n/m(n表示实际装载数据长度 m为表长)
    一般情况,假设hash函数是均匀的,则在讨论ASL时可以不考虑它的因素
    hash表的ASL是处理冲突方法和装载因子的函数
    前人已经证明,查找成功时如下结果:

    这里写图片描述
    可以看到无论哪个函数,装载因子越大,平均查找长度越大,那么装载因子α越小越好?也不是,就像100的表长只存一个数据,α是小了,但是空间利用率不高啊,这里就是时间空间的取舍问题了。通常情况下,认为α=0.75是时间空间综合利用效率最高的情况。

    上面的这个表可是特别有用的。假设我现在有10个数据,想使用链地址法解决冲突,并要求平均查找长度<2
    那么有1+α/2 <2
    α<2
    即 n/m<2 (n=10)
    m>10/2
    m>5 即采用链地址法,使得平均查找长度< 2 那么m>5

    之前我的博客讨论过各种树的平均查找长度,他们都是基于存储数据n的函数,而hash表不同,他是基于装载因子的函数,也就是说,当数据n增加时,我可以通过增加表长m,以维持装载因子不变,确保ASL不变。
    那么hash表的构造应该是这样的:

    这里写图片描述
    五、hash表的删除

    首先链地址法是可以直接删除元素的,但是开放定址法是不行的,拿前面的双探测再散列来说,假如我们删除了元素1,将其位置置空,那 23就永远找不到了。正确做法应该是删除之后置入一个原来不存在的数据,比如-1

    展开全文
  • 1、什么是链表 2、链表的三要素: 头指针(head):头指针用来说明链表的开始了,头指针就代表了链表本身,所以要访问链表,就要访问头指针。 头指针:就代表公司老板。老板就代表头指针。 结点(node):链表当中...

    链表:

    一、什么是链表:

    链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

    在这里要注意:

    首先看一下定义:
    -> :->是C语言和C++语言的一个运算符,叫做指向结构体成员运算符,用处是使用一个指向结构体或对象的指针访问其内成员。

    . 并不是一个运算符,它只是一个断点符号,它指向的是结构体或者对象。

    -> 是通过一个结构体或对象指针来访问他们的内部成员变量;
    .是直接通过结构体或对象来访问他们的内部成员变量。
    a->b读作a指向结构体的b
    a.b读作a的b

    二、链表的三要素:

    头指针(head):头指针是用来说明链表的开始了,头指针就代表了链表本身,所以要访问链表,就要访问头指针。
    头指针就代表公司老板。老板就代表头指针。
    结点(node):链表当中每一个变量被称为结点
    尾指针:用来说明链表结束(它是一个空指针,NULL)
    在这里插入图片描述
    注意:在定义结构体的时候有没有该结构类型的指针

    三、如果来创建一个链表

    1、用函数来创建一个链表(返回值为创建的那个链表,也就是要返回头指针 )
    举例:返回指针的函数
    函数返回指针就必须在该函数名称之前

    int *sum(int a,int b){//这个函数返回的是int类型指针
    }
    
    案例一、

    创建一个链表模拟图如下
    在这里插入图片描述

    #include<stdio.h> 
    #include<string.h> 
    typedef struct stud{
    	char Id[10];//学号 
    	char Name[10];//姓名
    	//这个指针的类型是结构体类型,以后这个指针就只能够指向struct stud这种结构体类型的变量 
    	struct stud *Next;
    }STU;
    //定义了一个返回值类型为结构体类型的函数 
    //因为传入的是地址值所以可以理解成为传入的是对象,即对应地址值内存当中的东西 
    STU *CreateLink(STU a[],int n)//要返回链表实际上就是要返回头指针 
    {
    	STU *head;//定义一个结构体类型的头指针 
    	head = &a[0];//把数组a当中的第一个元素地址值赋值给头,让头指针指向第一个结点
    	//用循环 把前一个结点与后一个结点通过next指针联系起来
    	//结点可以是一个对象,一个结构体,一个变量,一个指针地址 
    	int i;
    	for(i=0;i<n;i++){
    	//让每一个next结点 (结构对应的结果体指针)指向下一个结构的头结点 
    		a[i].Next=&a[i+1];
    	}
    	a[n-1].Next=NULL;//将结构体末尾指针指向的NULL 	
    	return head;//返回头指针 ,实际上就代表链表本身  
    } 
    //输出链表当中的所有结点的值 
    void OutputLink(STU *head){//参数是一个链表,这里的链表实际上就是需要头指针  
        //将链表的头指针赋值给指针p 
    	//head头指针不可以动,所以要将头指针的地址值赋值给p指针通过p指针来访问链表当中的数据
    	STU *p=head; 
    	printf("学号\t姓名\n");
    	while(p!=NULL){//当访问的结点不到末尾的时候 
    		printf("%s\t%s\n",p->Id,p->Name);
    		p=p->Next;//把指针p移动到下一个结点 
    	}
    } 
    void main(){
    	STU a[8]={
    	{"S1","张一军"}, 
    	{"S2","张二军"}, 
    	{"S3","张三军"}, 
    	{"S4","张四军"}, 
    	{"S5","张五军"}, 
    	{"S6","张六军"}, 
    	{"S7","张七军"},  
    	{"S8","张八军"}
    	},*head;
    	//现在还是只是一个数组不是链表,所以要调用 CreateLink来创建一个链表
    	head = CreateLink(a,8); 
    	OutputLink(head);
    }
    

    在这里插入图片描述

    查找在链表当中的一个指定的值

    #include<stdio.h> 
    #include<string.h> 
    typedef struct stud{
    	char Id[10];//学号 
    	char Name[10];//姓名
    	//这个指针的类型是结构体类型,以后这个指针就只能够指向struct stud这种结构体类型的变量 
    	struct stud *Next;
    }STU;
    //定义了一个返回值类型为结构体类型的函数 
    //因为传入的是地址值所以可以理解成为传入的是对象,即对应地址值内存当中的东西 
    STU *CreateLink(STU a[],int n)//要返回链表实际上就是要返回头指针 
    {
    	STU *head;//定义一个结构体类型的头指针 
    	head = &a[0];//把数组a当中的第一个元素地址值赋值给头,让头指针指向第一个结点
    	//用循环 把前一个结点与后一个结点通过next指针联系起来
    	//结点可以是一个对象,一个结构体,一个变量,一个指针地址 
    	int i;
    	for(i=0;i<n;i++){
    	//让每一个next结点 (结构对应的结果体指针)指向下一个结构的头结点 
    		a[i].Next=&a[i+1];
    	}
    	a[n-1].Next=NULL;//将结构体末尾指针指向的NULL 	
    	return head;//返回头指针 ,实际上就代表链表本身  
    } 
    //输出链表当中的所有结点的值 
    void OutputLink(STU *head){//参数是一个链表,这里的链表实际上就是需要头指针  
        //将链表的头指针赋值给指针p 
    	//head头指针不可以动,所以要将头指针的地址值赋值给p指针通过p指针来访问链表当中的数据
    	STU *p=head; 
    	printf("学号\t姓名\n");
    	while(p!=NULL){//当访问的结点不到末尾的时候 
    		printf("%s\t%s\n",p->Id,p->Name);
    		p=p->Next;//把指针p移动到下一个结点 
    	}
    } 
    void FindById(STU *head,char Id[]){//在一个链表当中查找指定的工号对应的值 	
    	//要访问链表当中的所有结点
    	STU *p = head;//把链表的头指针赋值给
    	while(p!=NULL){
    		//p就代表链表当中的每一个结点,如果p所指向的那个结点的id与我们要找的id相同的话,则要退出循环 
    		if(strcmp(p->Id,Id)==0){
    			break;//说明找到了,就退出循环,就没有必要再循环,就强制的退出循环。 
    		}				
    		p=p->Next;//这时指针指向的就是找到的结构体或者叫结点 
    	} 
    	// 退出循环之后,再来判断是否找到了
    	if(p==NULL){//表示没有找到 
    		printf("找不到此人");
    	}else{
    		//输出指针所指向那个结点的值
    		printf("%s\t%s\t",p->Id,p->Name); 
    	}	
    }
    void main(){
    	STU a[8]={
    	{"S1","张一军"}, 
    	{"S2","张二军"}, 
    	{"S3","张三军"}, 
    	{"S4","张四军"}, 
    	{"S5","张五军"}, 
    	{"S6","张六军"}, 
    	{"S7","张七军"},  
    	{"S8","张八军"}
    	},*head;
    	char Id[100]; 
    	//现在还是只是一个数组不是链表,所以要调用 CreateLink来创建一个链表
    	head = CreateLink(a,8); 
    	//输出链表 
    	OutputLink(head);
    	printf("请输入一个工号S1-S8:");	
    	gets(Id);//从键盘获取对应的Id以回车为结束
    	FindById(head,Id); 	 
    }
    

    在这里插入图片描述
    在这里插入图片描述

    删除指定的结点的链表

    删除结点的模拟图如下
    在这里插入图片描述

    #include<stdio.h> 
    #include<string.h> 
    typedef struct stud{
    	char Id[10];//学号 
    	char Name[10];//姓名
    	//这个指针的类型是结构体类型,以后这个指针就只能够指向struct stud这种结构体类型的变量 
    	struct stud *Next;
    }STU;
    //定义了一个返回值类型为结构体类型的函数 
    //因为传入的是地址值所以可以理解成为传入的是对象,即对应地址值内存当中的东西 
    STU *CreateLink(STU a[],int n)//要返回链表实际上就是要返回头指针 
    {
    	STU *head;//定义一个结构体类型的头指针 
    	head = &a[0];//把数组a当中的第一个元素地址值赋值给头,让头指针指向第一个结点
    	//用循环 把前一个结点与后一个结点通过next指针联系起来
    	//结点可以是一个对象,一个结构体,一个变量,一个指针地址 
    	int i;
    	for(i=0;i<n;i++){
    	//让每一个next结点 (结构对应的结果体指针)指向下一个结构的头结点 
    		a[i].Next=&a[i+1];
    	}
    	a[n-1].Next=NULL;//将结构体末尾指针指向的NULL 	
    	return head;//返回头指针 ,实际上就代表链表本身  
    } 
    //输出链表当中的所有结点的值 
    void OutputLink(STU *head){//参数是一个链表,这里的链表实际上就是需要头指针  
        //将链表的头指针赋值给指针p 
    	//head头指针不可以动,所以要将头指针的地址值赋值给p指针通过p指针来访问链表当中的数据
    	STU *p=head; 
    	printf("学号\t姓名\n");
    	while(p!=NULL){//当访问的结点不到末尾的时候 
    		printf("%s\t%s\n",p->Id,p->Name);
    		p=p->Next;//把指针p移动到下一个结点 
    	}
    } 
    //链表的删除
    /*
    1、必须要找到要删除的结点
    2、删除对应的结点
    3:该函数要返回删除之后的新链表,实际上是返回头指针 
    */ 
    STU *DelById(STU *head,char Id[]){//根据工号删除对应链表中的一个结点 
    	//必须要找到该结点
    	STU *p=head,*front;
    	while(p!=NULL){
    		if(strcmp(p->Id,Id) == 0){//如果p所指向的结点等于Id要删除的Id的话 
    			break;//就退出循环 
    		}
    		//在p移动之前,要保留以前的位置
    		front=p; 
    		p=p->Next;//p移动到下一个结点 
    	} 
    	if(p!=NULL){//找到了要删除的结点
    		front->Next=p->Next; 
    	}
    	return head;
    }
    void main(){
    	STU a[8]={
    	{"S1","张一军"}, 
    	{"S2","张二军"}, 
    	{"S3","张三军"}, 
    	{"S4","张四军"}, 
    	{"S5","张五军"}, 
    	{"S6","张六军"}, 
    	{"S7","张七军"},  
    	{"S8","张八军"}
    	},*head;
    	char Id[100]; 
    	//现在还是只是一个数组不是链表,所以要调用 CreateLink来创建一个链表
    	head = CreateLink(a,8); 
    	//输出链表 
    	OutputLink(head);
    	printf("请输入一个工号S1-S8:");	
    	gets(Id);//从键盘获取对应的Id以回车为结束
    	head = DelById(head,Id);//表示在调用 DelById在删除一个结点,但是看不到效果
    	//再次输出对应的链表 
    	OutputLink(head);
    }
    

    在这里插入图片描述

    链表的插入(向链表当中插入元素)

    1、找到要插入链表的位置(有两个位置)
    2、执行插入操作
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    算法实现

    #include<stdio.h> 
    #include<string.h> 
    typedef struct stud{
    	char Id[10];//学号 
    	char Name[10];//姓名
    	int Age;//年龄 
    	//这个指针的类型是结构体类型,以后这个指针就只能够指向struct stud这种结构体类型的变量 
    	struct stud *Next;
    }STU;
    //定义了一个返回值类型为结构体类型的函数 
    //因为传入的是地址值所以可以理解成为传入的是对象,即对应地址值内存当中的东西 
    STU *CreateLink(STU a[],int n)//要返回链表实际上就是要返回头指针 
    {
    	STU *head;//定义一个结构体类型的头指针 
    	head = &a[0];//把数组a当中的第一个元素地址值赋值给头,让头指针指向第一个结点
    	//用循环 把前一个结点与后一个结点通过next指针联系起来
    	//结点可以是一个对象,一个结构体,一个变量,一个指针地址 
    	int i;
    	for(i=0;i<n;i++){
    	//让每一个next结点 (结构对应的结果体指针)指向下一个结构的头结点 
    		a[i].Next=&a[i+1];
    	}
    	a[n-1].Next=NULL;//将结构体末尾指针指向的NULL 	
    	return head;//返回头指针 ,实际上就代表链表本身  
    } 
    //输出链表当中的所有结点的值 
    void OutputLink(STU *head){//参数是一个链表,这里的链表实际上就是需要头指针  
        //将链表的头指针赋值给指针p 
    	//head头指针不可以动,所以要将头指针的地址值赋值给p指针通过p指针来访问链表当中的数据
    	STU *p=head; 
    	printf("学号\t姓名\t年龄\n");
    	while(p!=NULL){//当访问的结点不到末尾的时候 
    		printf("%s\t%s\t%d\n",p->Id,p->Name,p->Age);
    		p=p->Next;//把指针p移动到下一个结点 
    	}
    } 
    //插入一个结点,并且要返回插入之后的链表 
    STU *Insert(STU *head,STU *pNewNode)
    {
    	STU *p,*front;
    	p=head;
    	while(p!=NULL && p->Age < pNewNode->Age){//如果发现p所指向的年龄比新节点的年龄要小的话,就不断循环 
    		p=p->Next;
    	} 
    	//退出循环之后,我们要来检查p的状态
    	if(p==head){//说明新的结点一个插入到开头
    		//新节点的next要指向以前的head 
    		pNewNode->Next=head; 
    		//新的head要指向插入的节点  
    		head=pNewNode;
    	} else{
    		if(p==NULL)//说明新的节点应该插入到末尾
    		{
    			front->Next=pNewNode;//把front的next指向新节点的 
    			pNewNode->Next=NULL;//在把新节点的next赋值为NULL 
    		} else{//在中间插入 (p前面插入)
    			//把front的next指向新节点
    			front->Next=pNewNode;
    			//把新结点的next指向p
    			pNewNode->Next=p; 
    		}
    		return head;//返回头指针,就是返回链表 
    	}
    }
    
    void main(){
    	STU a[8]={
    	{"S1","张一军",23}, 
    	{"S2","张二军",24}, 
    	{"S3","张三军",25}, 
    	{"S4","张四军",26}, 
    	{"S5","张五军",27}, 
    	{"S6","张六军",29}, 
    	{"S7","张七军",30},  
    	{"S8","张八军",31}
    	},*head,NewNode={"S9","小小样",12},*pNewNode=&NewNode;
    	char Id[100]; 
    	//现在还是只是一个数组不是链表,所以要调用 CreateLink来创建一个链表
    	head = CreateLink(a,8); 
    	//输出链表 
    	OutputLink(head);
    	pNewNode = Insert(head,pNewNode);
    	OutputLink(pNewNode);
    }
    

    在这里插入图片描述

    展开全文
  • 数据结构-静态查找表

    2019-09-25 10:04:17
    一、 查找概念 假设有两组数据: int array1[]={6,4,5,3,8,7,1,2,0,9}; int array2[]={0,1,2,3,4,5,6,7,8,9}; 一个有序数组,一个无序数组, 在他们之间查找某一个值的...思路怎么样的呢:从中最后一个记录开始...

     

     

     

    一、  查找概念

    假设有两组数据:

    int array1[]={6,4,5,3,8,7,1,2,0,9};

    int array2[]={0,1,2,3,4,5,6,7,8,9};

    一个有序数组,一个无序数组, 在他们之间查找某一个值的方法有什么区别呢,

    对于两组数据我们都可以用最直接的方法,逐个比较直到遇到合适的值。

    思路是怎么样的呢:从表中最后一个记录开始,逐个进行记录的关键字和给定值的比较,若某个记录的关键字和给定值比较相等,则返回返回记录所在的位置,或查找完所有记录后还没有发现符合的记录,则查找失败。我们称其为顺序查找。

    当数据是一个有序的情况时,我们可以利用这样一种思路:当记录的key按关系有序时可以使用折半查找

    对于给定key值,逐步确定待查记录所在区间,每次将搜索空间减少一半(折半), 直到查找成功或失败为止。我们称其为折半查找。

    若要利用计算机帮助我们实现查找的过程,就需要我们了解查找的相关知识.

    查找:查询(Searching)特定元素是否在表中。

    查找表:由同一类型的数据元素(或记录)构成的集合。

    查找成功:若表中存在特定元素,称查找成功,应输出该记录;

    查找失败:否则,称查找不成功(也应输出失败标志或失败位置)。

    静态查找表:只查找,不改变集合内的数据元素。

    动态查找表:既查找,又改变(增减)集合内的数据元素。

    关键字:记录中某个数据项的值,可用来识别一个记录。

    主关键字:可以唯一标识一个记录的关键字。例如:学号

    次关键字:识别若干记录的关键字。例如:女

    二、  顺序表查找

       顺序查找( Linear search,又称线性查找 )用逐一比较的办法顺序查找关键字,这显然是最直接的办法。

    1. 1.        顺序表查找算法

    顺序查找算法:

    int Search_Seq( int  *a , int n,int  key )
    {
    for( i=1;i<=n;  i++)
    {
                if(key==a[i])
    {
                    return i;
    }
    }
          return 0;
    } 

    这里元素都放在数组下标为1的地方开始,返回0意味着查找失败,比较的时候只要注意key的数据类型就可以了。

    1. 1.        顺序表查找优化//比较次数减少

    改进后的顺序查找算法

    int Search_Seq( int  *a , int n,int  key )
    {
         int i=n;     //指向表尾部
         a[0]=key;   //把待查记录放在a[0]中做监视哨
    while(a[i]!=key)
    {
       i--;
    }
    return i;    /*返回0 意味着失败*/
    } 

    这里免去数组越界的判断,从末端开始查找,当数据记录较多的时候能够大大的提高效率,可以注意这种编程技巧。

    1.        顺序查找的平均查找长度

     

    顺序查找平均查找长度(ASL  Average Search Length),假设查找的表中有n个元素,查找每个元素的概率相等,那么查找第一个元素的次数是1次,查找第二个元素的次数是2次,以此类推查找第n个元素的次数是n次。则总的查找次数为:1+2+3+...+n。这是一个等差数列,求得和后为(1+n*n/2;再由于n种情况的概率一样,则平均起来计算为

    因此得到顺序查找的平均查找长度的结论是: (n+1)/2。

    一、  有序表查找

    1. 1.        折半查找

    折半查找前提是顺序存储,记录有序。

    思想:与记录中间值比较,如果比中间值小去左边查,否则去右边查找,直到找到为止,区域内没记录时查找失败。

    算法:

    int Binary_Search( int  *a , int n,int  key )
    {
         int low,high,mid;
         low=1;
         high=n;
    while(low<=high)
    {
            mid=(low+high)/2;   //定位中间的记录 
            if(key<a[mid])
                high=mid-1;    //小于中间记录high移到mid左边即mid-1
    else if(key>a[mid])
                low=mid+1;    //大于中间记录high移到mid右边即mid+1
    else
            return mid;
    }
    return 0;    /*返回0 意味着失败*/
    }

    这两种查找方式的主要区别:

     

    1. 2.        折半查找的平均查找长度

    折半查找的平均查找长度分析:由于折半查找算法的特点,没次会抛弃约一半的数据,在剩余一半里继续使用折半查找,因此每次都是前一次的约一半的关系。则可以得出折半查找的平均查找长度约为log2n ,记为:

     代码折半查找

    /* Note:Your choice is C IDE */
    #include "stdio.h"
    int  binarysearch(int a[],int c){
        int low,high,mid;
        high=14;
        low=0;
        while(low<=high){
            mid=(low+high)/2;
            if(a[mid]>c){
            high=mid-1;
            }else if(a[mid]<c){
            low=mid+1;
            }else{
            return mid;
            }
        }
        return-1; 
    }
    void main()
    {
        int a[]={1,2,4,5,8,9,12,15,18,25,36,42,52,62,85};
        int c;
        scanf("%d",&c);
        printf("%d\n",binarysearch(a,c));
    }

    代码-字符定位

    #include "stdio.h"
    #include "string.h"
    int sort(char s[],char sb[],int sta){//sta 为开始查找处
        int i=sta,j=0;
        while(i<(strlen(s))&&j<strlen(sb)){
            if(s[i]==sb[j])
            {
                i++;
                j++;
            }else{
               i=i-j+1;//将开始往后移
               j=0;
            }
        }
        if(j==strlen(sb)){
            return i-strlen(sb);
        }else{
        return -1;}
        }
    void main()
    {
        int sta=0,len,o;
        char sb[20];
        char s[100]="theanswertoyourkuestionisyes";
        printf("输入字符串:");
        scanf("%s",sb);
        fflush(stdin);
        o=sort(s,sb,sta);
        printf("%d",o);
    }

     

    转载于:https://www.cnblogs.com/TimVerion/p/11206183.html

    展开全文
  • 前面说了折半查找,那为什么是折半而不是四分之一或者别的呢? 折半查找的代码中 mid 的赋值经过变换得到: 也就是mid 等于最低下标low 加上最高下标 hign 与 low 的差的一半。 算法科学家就是考虑将这个进行...
  • 目录链表:随机存储,顺序访问(读取)前言一、单向链表什么叫随机存储呢?链表的基本操作1. 查找节点2. 更新节点3. 插入节点3.1. 尾部插入3.2. 头部插入3.3. 中间插入4. 删除元素4.1. 尾部删除4.1. 头部删除4.1. ...
  • 数据结构总结之三—动态查找表 1.前言 提到动态的话,就要想到链表了,所以这一次主要总结,在链表上如何实现查找。 2.二叉排序树 2.1什么是二叉排序树 若树的左子树不为空,那么左子树上所有节点的值均小它的根...
  • 当用动态分配进行查找时data变量为一个指针指向数据中第一个数据元素也用malloc函数申请顺序的一整个存储空间虽然data变量一个指针但也会像数组一样用下标的方式指向存储空间的元素 如果说指针所对应的变量...
  • 数组也有一定的缺点的,如果我们不知道某个元素的下标值,而只是知道该元素在数组中,这时我们想要获取该元素就只能对数组进行线性查找,即从头开始遍历,这样的效率非常低的 所以,为了解决上述数组的不足之处...
  • 链表 [Linked List]:链表由一组不必相连【不必相连:可以连续也可以不连续】的内存结构 【节点】,按特定的顺序链接在一起的抽象数据类型。链表常用的有 3 类: 单链表、双向链表、循环链表。链表的核心操作集有 ...
  • [数据结构]什么是链表?

    千次阅读 2019-07-14 22:52:52
    链表一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序通过链表中的指针链接次序实现的–百度百科 大致分为单链表和双向链表 1.单链表:每个节点包含两部分,一部分存放数据变量的data,另一部分...
  • !! @哈希的实际应用 1,Sql中的索引,就是通过哈希实现的。加大了数据存储空间,但查询速度快了很多!...@什么是哈希? 1,google搜索到的头条:  散列表(也叫哈希),根据关键码值直接...
  • 什么是顺序查找呢?顺序查找的原理很简单,就是遍历整个列表,逐个进行记录的关键字与给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录。如果直到最后一个记录,其关键字和给定值比较都不等...
  • ``` Status LocateElem(SqList L,ElemType e,Status(*compare)(ElemType,ElemType)) { ElemType *p; int i=1; p = L.elem ; while(i!compare(*p++,e)) ... 这个是什么意思,要执行这个子函数要怎么传值?
  • 「引出Hash」:理想的情况希望不经过任何比较,一次存取便能得到所查记录,那就必须在记录的存储位置和它的关键字之间建立一个确定的关系ff,使每个关键字和结构中一个唯一的存储位置相对应。因而在查找时,只要...
  •   说实话跳跃表是我非常喜欢的数据结构,虽然很多数据结构和算法的书中并没有讲它,为什么喜欢呢?因为我觉得它最好玩,为什么好玩呢?我也不知道,就是觉得好玩。好了,说了几句废话,现在言归正传。我们之前说过...
  • 符号表是一种非常常见的容器的一种,或者叫变体。符号表也是存储东西的结构。只不过符号表存储的东西有点特别。它存的就是大名鼎鼎的“键值对”!俗称:key-value符号表也就是key-value组成的集合。Key-value为什么...
  • 查找是基于二叉排序树的,先来看看二叉排序树是什么 二叉排序树(Binary sort tree) 又称二叉查找树,也称二叉搜索树,它的特征是 若它的左子树非空,则左子树上所有结点值(指关键字值)均小于根结点值; ...
  • 核心的地方就是这个函数是什么,构造不同的函数,你得出的结果肯定是不同的。同时还存在一个问题,就是你得到了两个y值,并且它们还都一样,这时你就得再构造一个函数来区别它们,这种情况在数据结构里称作同义词...
  • 什么是哈希,按内容存储。内容直接到存储地址。 哈希函数:实际上根据实际情况构造的。 处理冲突:线性探查法,冲突后直接向下线性找一个新的空间存放。 双散列函数:冲突后执行另一个散列函数 拉链法:...
  • 然而它与线性表、树、图等结构不同的,前面几种结构,数据元素之间都存在某种逻辑关系,可以用连线图示表示出来,而哈希技术的记录之间不存在什么逻辑关系,它只与关键字有关联。因此,哈希主要面向查找的存储...
  • 欢迎关注我的公众号...哈希的建立同函数类似,把函数中的 x 用查找记录时使用的关键字来代替,然后将关键字的值带入一个精心设计的公式中,就可以求出一个值,用这个值来表示记录存储的哈希地址。即: 数...
  • 什么HashMap链表长度超过8会转成树结构? HashMap在JDK1.8及以后的版本中引入了红黑树结构,若桶中链表元素个数大于等于8时,链表转换成树结构;若桶中链表元素个数小于等于6时,树结构还原成链表。因为红黑树的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,767
精华内容 1,506
关键字:

查找表是什么结构