数据结构相关知识上

来源:互联网 发布:擎洲广达云计价软件 编辑:程序博客网 时间:2024/06/08 05:34
数据结构

顺序存储结构:数组
1,所有元素紧密排列在同一个内存中
2,逻辑结构内的前驱后继关系对应存储结构也是前驱后继关系
链式存储结构:指针
1,所有元素不一定要紧密排列在同一块内存中
2,逻辑结构内的前驱后继关系不一定严格对应存储结构的前驱后继关系。
以下为我程序编写的命名方式:
sq:顺序
link:链式
list:线性结构
tree:树形结构
create:创建
insert:插入
delete:删除
clear:清除。
时间复杂度:评价算法好坏的指标
指的是算法随着数据量的增加,算法的运行时间增加速率的快慢。
计算时间复杂度:
1,计算语句频度T(n)
T(n)算法在执行期间一共执行多少条语句。
2,T(n)是一个多项式,保留多项式的最高次项其他项省略。
3,如果多项式的最高次项系数不是1,则优化为1.


下面是我所编写的双向链表:仅供参考


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define OK 1
#define ERROR 0
typedef struct link
{
int data;
struct link *prior;
struct link *next;


}Link,*LinkList;
//创建一个空的头节点
LinkList CreatedHead()
{
LinkList p;
p=(LinkList)malloc(sizeof(Link));
if(!p)
{
printf("created fail\n");
return ERROR;
}
p->prior=NULL;
p->next=NULL;
return p;
}


//创建一个空链表链接在头节点后
LinkList CreateLink(LinkList L)
{
LinkList p,s;
p=L;
while(p->next!=NULL)
{
p=p->next;
}
s=(LinkList)malloc(sizeof(Link));
printf("请输入您要输入的链表的数据\n");
scanf("%d",&(s->data));
p->next=s;
s->prior=p;
p=s;
s->next=NULL;
return L;


}
//对链表进行插入操作
LinkList LinkInsert(LinkList L,int i,int *e)
{
LinkList p,q;
int j=1;
p=L;
while(p&&j<i)
{
p=p->next;
j++;
}
printf(">>>>>>>>>>>>>>\n");
q=(LinkList)malloc(sizeof(Link));
if(!q)
{
printf("malloc fail\n");
return ERROR;
}
q->next=p->next;
p->next->prior=q;
q->prior=p;
p->next=q;
q->data=(*e);
printf(".............\n");
return L;


}
//对链表进行查询操作
int LinkSearch(LinkList L,int i,int m)
{

LinkList p;
int j=1;
p=L->next;
if(!p)
{
printf("链表为空哦!\n");
return ERROR;
}


while(p&&j<i)
{
p=p->next;
j++;
}
if(!p)
{
printf("输入错误哦!超出链表长度了\n");
return ERROR;
}
m=p->data;
return m;


}
//对整个链表进行删除
LinkList Delete(LinkList L)
{
LinkList p,q;
p=L->next;
q=p;
while(p)
{
q=q->next;
free(p);
p=q;
}
return L;
}


//对整个链表进行遍历
int print(LinkList L)
{
LinkList p=L->next;
if(!p)
{
printf("链表为空\n");
return ERROR;
}
while(p)
{
printf("%d\t",p->data);
p=p->next;
}
return OK;


}
int main(int argc, const char *argv[])
{
LinkList head;
int i,m,n;
head=CreatedHead();
for(i=1;i<=5;i++)
{
head=CreateLink(head);
}
m=3;
LinkInsert(head,2,&m);
n=LinkSearch(head,3,n);
printf("链表取出的数据为%d\n",n);


print(head);
Delete(head);
print(head);
return 0;
}
查找
一、查找概论
各位都用过搜索引擎。搜索引擎的大概工作原理就是利用网络“爬虫”抓取并复制网页,并且可以通过该网页的链接来抓取更多的网页。
那么,搜索引擎的是通过什么来抓取网页的呢?就是通过“关键字”来识别网页并抓取网页的。


查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。
查找表(Search Table)是由同一类型的数据元素(或记录)构成的集合。
关键字(Key)是数据元素中某个数据项的值,又称为键值,用它可以标识一个数据元素,也可以标识一个记录的某个数据项(字段)。
若此关键字可以唯一地标识一个记录,则称此关键字为主关键字(Primary Key)。对于那些可以识别多个数据元素(或记录)的关键字,我们称为次关键字(Secondary Key)。
例如,若将一张成绩单作为查找表,则学号或姓名都可以作为主关键字,因为它们可以唯一确定一个查找记录。而成绩则只能作为次关键字,因为不能唯一确定一个查找记录。


二、顺序表查找
顺序查找(Sequential Search)又叫线性查找,是最基本的查找技术,它的查找过程是:从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查记录;如果直到最后一个(或第一个)记录,其关键字和给定值比较都不等时,则表中没有所查的记录,查找不成功。
1、顺序表查找算法
#include <stdio.h>
#include <stdlib.h>
int number[11]={0,12,16,24,35,47,59,62,73,88,99};//待查表,第一个元素是哨兵位而不是待查数据,待查数据从下标1(第二个元素)开始
int Sequential_Search(int *a,int n,int key)
{
    int i;
    for(i=1;i<=n;i++)
    {
        if(a[i]==key)
            return i;//返回查找到的下标
    }
    return 0;//返回0代表查找失败
}
int Sequential_Search2(int *a,int n,int key)
{
    int i;
    a[0]=key;//设置哨兵
    i=n;
    while(a[i]!=key)
    {
        i--;
    }
    return i;//返回0则查找失败
}
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;
        else if(key>a[mid])
            low=mid+1;
        else
            return mid;
    }
    return 0;
}
int Interpolation_Search(int *a,int n,int key)//插值查找
{
    int low,high,mid;
    low=1;
    high=n;
    while(low<=high)
    {
        mid=low+(high-low)*(key-a[low])/(a[high]-a[low]);
        if(key<a[mid])
            high=mid-1;
        else if(key>a[mid])
            low=mid+1;
        else
            return mid;
    }
    return 0;
}
int main()
{
    int position;
    //position = Binary_Search(number,10,47);
    //printf("Position is %d\n",position);
    return 0;
}
这段代码比较简单。需要注意的是待查表的数据是从下标1开始的。
2、顺序表查找算法优化
上文所给的算法并非完美,因为每次循环时都需要对i是否越界(即i<=n)进行判断。事实上,我们有更优化的算法。设置一个哨兵,可以解决不需要每次让i与n进行比较。
//代码见附录
此时代码是从尾部开始查找,由于a[0]等于key,也就是说,一定会找到key值的位置,要么是在某个非0位置(表示成功),要么是0(表示失败)。
这种方式是在查找数据的尽头设置“哨兵”免去了每次比较数据后都需要判断数据是否越界,看似差别与原先不大,但在数据量较大时,效率提高很大,是非常常用的技巧。


三、有序表查找
我们可以做一个游戏:给定一个100以内正整数让你猜,我只说“大了”或“小了”。对于这个游戏,从1开始依次数到100当然可以,但是效率太低。我们可以先猜50,然后针对“大了/小了”再决定下次猜的数字(25或75)。我们把这种每次取中间记录的查找方法叫做折半查找
折半查找(Binary Search),又称为二分查找。它的前提是线性表中的记录必须是关键字有序,而且线性表必须采用顺序存储。
折半查找的基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录关键字,则在中间记录的左半区进行查找;若给定值大于中间记录的关键字,则在中间记录的右半区进行查找。不断重复上述过程直至查找成功(或失败)为止。
//代码见附录
由于折半查找的前提是需要有序表存储,因此如果某个数据表需要频繁执行插入或删除操作,维护其有序需要不小的工作量,这时不推荐使用折半查找。


四、散列表(哈希表)查找
上文中介绍的查找方法,都需要“比较”。我们发现,为了查找结果,“比较”是不可避免的,但是否真的有必要呢?
1、散列表查找定义
试想这样的场景:你来到某所不熟悉的学校,想要找一个叫“盖伦”的同学。有两种方法:
1)询问教务处的老师,老师会拿出学生名册,从上到下查找,最终告诉你:“盖伦”同学在德玛西亚班
2)去操场打听认识“盖伦”的同学,他会告诉你:“盖伦”同学在德玛西亚班
以上两种方法都可以查到“盖伦”同学的位置,第一种方法就是常规的查找方法,而第二种方法就是散列表查找方法。
也就是说,我们只需要得到某个函数f(),使得:
存储位置=f(关键字);
那样我们就可以不用通过比较关键字来查找存储位置,而是直接通过该函数算出存储位置。这就是另一种存储技术——散列技术。
对应函数f称为散列函数,又称为哈希(Hash)函数。使用散列技术将记录存储在一块存储空间中,这块存储空间就称为散列表或哈希表(Hash Table)。关键字所对应的记录存储位置就称为散列地址。


原创粉丝点击