您的位置:首页 > 理论基础 > 数据结构算法

数据结构的基本概念 单链表的应用

2014-03-05 20:30 357 查看
什么是数据结构 ?

答:1.数据结构是计算机存储、组织组织的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法索引技术有关。



2.数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。记为:

Data_Structure=(D,R)

其中D是数据元素的集合R是该集合中所有元素之间的关系的有限集合

研究对象包括哪些?



一、数据的逻辑结构:指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后件关系,而与他们在计算机中的存储位置无关。逻辑结构包括:

1.集合

2.线性结构

3.树形结构

4.图形结构

二、数据的物理结构:指数据的逻辑结构在计算机存储空间的存放形式。

重要意义??





答:一般认为,一个数据结构是由数据元素依据某种逻辑联系组织起来的。对数据元素间逻辑关系的描述称为数据的逻辑结构;数据必须在计算机内存储,数据的存储结构是数据结构的实现形式,是其在计算机内的表示;此外讨论一个数据结构必须同时讨论在该类数据上执行的运算才有意义。一个逻辑数据结构可以有多种存储结构,且各种存储结构影响数据处理的效率。

在许多类型的程序的设计中,数据结构的选择是一个基本的设计考虑因素。许多大型系统的构造经验表明,系统实现的困难程度和系统构造的质量都严重的依赖于是否选择了最优的数据结构。许多时候,确定了数据结构后,算法就容易得到了。有些时候事情也会反过来,我们根据特定算法来选择数据结构与之适应。不论哪种情况,选择合适的数据结构都是非常重要的。

选择了数据结构,算法也随之确定,是数据而不是算法是系统构造的关键因素。这种洞见导致了许多种软件设计方法和程序设计语言的出现,面向对象的程序设计语言就是其中之一。



结构分类




数据结构是指同一数据元素类中各数据元素之间存在的关系。数据结构分别为逻辑结构存储结构物理结构)和数据的运算。数据的逻辑结构是对数据之间关系的描述,有时就把逻辑结构简称为数据结构。逻辑结构形式地定义为(K,R)(或(D,S)),其中,K是数据元素的有限集,R是K上的关系的有限集。

根据数据元素间关系的不同特性,通常有下列四类基本的结构: ⑴集合结构。该结构的数据元素间的关系是“属于同一个集合”。 ⑵线性结构。该结构的数据元素之间存在着一对一的关系。 ⑶树型结构。该结构的数据元素之间存在着一对多的关系。 ⑷图形结构。该结构的数据元素之间存在着多对多的关系,也称网状结构。 从上面所介绍的数据结构的概念中可以知道,一个数据结构有两个要素。一个是数据元素的集合,另一个是关系的集合。在形式上,数据结构通常可以采用一个二元组来表示。

数据结构的形式定义为:数据结构是一个二元组 :Data_Structure=(D,R),其中,D是数据元素的有限集,R是D上关系的有限集。线性结构的特点是数据元素之间是一种线性关系,数据元素“一个接一个的排列”。在一个线性表数据元素的类型是相同的,或者说线性表是由同一类型的数据元素构成的线性结构。在实际问题中线性表的例子是很多的,如学生情况信息表是一个线性表:表中数据元素的类型为学生类型;
一个字符串也是一个线性表:表中数据元素的类型为字符型,等等。

线性表是最简单、最基本、也是最常用的一种线性结构。 线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列,通常记为: (a1,a2,… ai-1,ai,ai+1,…an) ,其中n为表长, n=0 时称为空表。 它有两种存储方法:顺序存储和链式存储,它的主要基本操作是插入、删除和检索等。

数据结构在计算机中的表示(映像)称为数据的物理(存储)结构。它包括数据元素的表示和关系的表示。数据元素之间的关系有两种不同的表示方法:顺序映象和非顺序映象,并由此得到两种不同的存储结构:顺序存储结构和链式存储结构

顺序存储方法:它是把逻辑上相邻的结点存储在物理位置相邻的存储单元里,结点间的逻辑关系由存储单元的邻接关系来体现,由此得到的存储表示称为顺序存储结构。顺序存储结构是一种最基本的存储表示方法,通常借助于程序设计语言中的数组来实现。

链接存储方法:它不要求逻辑上相邻的结点在物理位置上亦相邻,结点间的逻辑关系是由附加的指针字段表示的。由此得到的存储表示称为链式存储结构,链式存储结构通常借助于程序设计语言中的指针类型来实现

索引存储方法:除建立存储结点信息外,还建立附加的索引表来标识结点的地址

散列存储方法:就是根据结点的关键字直接计算出该结点的存储地址。

数据结构中,逻辑上(逻辑结构:数据元素之间的逻辑关系)可以把数据结构分成线性结构和非线性结构。线性结构的顺序存储结构是一种顺序存取的存储结构,线性表的链式存储结构是一种随机存取的存储结构。线性表若采用链式存储表示时所有结点之间的存储单元地址可连续可不连续。逻辑结构与数据元素本身的形式、内容、相对位置、所含结点个数都无关。



常用结构





数组 (Array)

在程序设计中,为了处理方便, 把具有相同类型的若干变量按有序的形式组织起来。这些按序排列的同类数据元素的集合称为数组。在C语言中,
数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。


栈 (Stack)

是只能在某一端插入和删除的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。


队列 (Queue)

一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列是按照“先进先出”或“后进后出”的原则组织数据的。队列中没有元素时,称为空队列。


链表 (Linked List)

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


树 (Tree)

是包含n(n>0)个结点的有穷集合K,且在K中定义了一个关系N,N满足 以下条件:

(1)有且仅有一个结点 K0,他对于关系N来说没有前驱,称K0为树的根结点。简称为根(root)。  (2)除K0外,K中的每个结点,对于关系N来说有且仅有一个前驱。

(3)K中各结点,对关系N来说可以有m个后继(m>=0)。



图 (Graph)

图是由结点的有穷集合V和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。


堆 (Heap)

在计算机科学中,堆是一种特殊的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。



散列表 (Hash)

若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为散列函数(Hash function),按这个思想建立的表为散列表

关于数据结构的简单例子



/*

 ============================================================================

 Name        : D_LinkList.c

 Author      : 谷建鹏

 Version     :

 Copyright   : Your copyright notice

 Description : Hello World in C, Ansi-style

 ============================================================================

 */

#include <stdio.h>

#include <stdlib.h>

typedef int DataType; //将int类型重新定义一个新的类型DataType

typedef struct LNode{ //定义结构体,实际上就是结点
DataType data;
//定义数据域

    struct LNode *next; //定义指针域

}LinkList;

//再定义一个结点

typedef LinkList Node;

/*

 * 功能:创建并且初始化

 * 参数:整数,用于创建第一个结点

 * 返回值:返回头指针

 * 思路:

 * 1)先要创建头指针

 *    (1)头指针的数据域 存放当前线性表的长度

 *    (2)指针域指向空

 * 2)创建第一个结点

 *    (1)数据域 存 函数传递过来的参数

 *    (2)指针域指向空

 *    (3)修改头指针的指向为新创建的指针

 * 3)返回头指针

 */

LinkList * Create_LinkList(DataType data){ //创建头指针

LinkList *head = (LinkList *)malloc(sizeof(LinkList));
if(head!=NULL){

        Node *p = (Node*)malloc(sizeof(Node));
//创建第一个结点

        if(p!=NULL){

p->data = data;
p->next = NULL;
//设定数据域和指针域

head->next = p;
//设定头指针的指针域
head->data = 1;
//设定头指针的数据域

        }else{

        printf("第一个结点创建失败!\n");

        }

        //返回头结点的指针

        return head;
}else{
printf("头结点创建失败!\n");
return NULL;
}

}

/*

 * 功能:打印线性链表

 * 参数:LinkList *head  (线性链表的头指针)

 * 返回值:void

 * 思路:

 * 1)定义一个指针变量,获取第一个元素(p = head->next)

 * 2)循环遍历,条件是:p->next!=NULL

 * 3)打印p指向的数据域  :p->data

 */

void Print_LinkList(LinkList *head){
//定义一个指针变量,让其指向线性链表的第一个元素
Node *p = head->next;       //head->next肯定是第一个元素
while(p!=NULL){
printf("%d\t",p->data);

        p=p->next; //让p向下移动
}
printf("\n");

}

/*

 * 功能:线性单链表的添加新的元素

 * 参数:LinkList *head,DataType data

 * 返回值:void

 * 思路:

 * 插入一个元素到我们的线性链表中,有两种方法:

 * 头插法

 *    每次在头结点之后插入一个元素

 * 尾插法(作业)

 *    每次在最后一个元素之后插入新的元素

 *

 * 使用头插法,实现新元素的插入的步骤:

 * 1)先给新元素申请内存空间

 * 2)设置新元素的数据域和指针域

 * 3)设置头指针数据域和指针域

 *

 */

void Insert_LinkList(LinkList *head,DataType data){
//申请新的空间
Node *new = (Node*)malloc(sizeof(Node));
if(new!=NULL){

new->data = data;
//设定新的元素的数据域和指针域
new->next = head->next;

head->next = new;
//让head执行新添加的数据
head->data++;
}else{
printf("插入数据,空间申请失败!\n");
}

}

/* 功能:删除结点

 * 参数:LinkList *head,DataType data

 * 返回值:int (返回删除数据所在的位置)

 * 思路:

 * 1、根据头指针的指向,找到第一个元素,并且定义一个新的指针指向它

 * 2、判断要删除的是否是第一个结点

 * 3、如果不是第一个结点

 */

int Delete_LinkList(LinkList *head,DataType data){
Node *p = head->next;  //p指向了第一个结点
//进行删除的时候临时存储结点的信息

    Node *temp;

    int loc=0;

    while(p!=NULL){

        loc++;

    //判断要删除的是不是当前元素

    if(p->data == data){

    //把第二个元素的信息存储到temp中

    temp = p->next;

    free(p);

    head->next = temp;

    head->data --;

    break;

    }else if(p->next->data == data){

    //判断是不是下一个元素

    temp = p->next;

    p->next = p->next->next;

    free(temp);

    head->data --;

    loc++;

    break;

    }else{

       //指针下移

    p = p->next;

    }

    }

    return loc;

}

/* 功能:按值查找

 * 参数:LinkList *head,DataType data

 * 返回值:int 位置

 * 思路:

 * 1)定义一个指针变量,让其指向第一个元素

 * 2)判断指针指向的值,是否等于要查找的值

 * 3)如果等于,则返回位置,如果不等于则指针下移   p = p->next;

 */

int SearchByData_LinkList(LinkList *head,DataType data){

Node *p  = head->next;
int loc=0;
while(p!=NULL){

        loc++;

        //判断当前指针指向的值是否是要查找的值,如果是,则停止
if(p->data == data){
break;
}else{
//如果不是,则指针下移
p = p->next;
}

}

return loc;

}

/* 功能:按值查找

 * 参数:LinkList *head,DataType oldData,DataType newData

 * 返回值:void

 * 思路:

 * 1)定义一个指针变量,让其指向第一个元素

 * 2)判断指针指向的值,是否等于要查找的值

 * 3)如果等于,则修改原来的值=新的值(p->data=newData),如果不等于则指针下移   p = p->next;

 */

void ModifyByData_LinkList(LinkList *head,DataType oldData,DataType newData){

Node *p  = head->next;

while(p!=NULL){

        //判断当前指针指向的值是否是要查找的值,如果是,则停止
if(p->data == oldData){
//修改当前指针的值为要修改的值
p->data = newData;
break;
}else{
//如果不是,则指针下移
p = p->next;
}
}

}

int main(void) {

//定义线性链表,并且初始化
LinkList *llist = Create_LinkList(7);
//打印线性表的内容

    Print_LinkList(llist);

    //插入数据

    Insert_LinkList(llist,58);

    Print_LinkList(llist);

    Insert_LinkList(llist,90);

    Insert_LinkList(llist,88);

    Insert_LinkList(llist,60);

    Print_LinkList(llist);

    Delete_LinkList(llist,60);

    Print_LinkList(llist);

    printf("删除的位置是:%d\n",Delete_LinkList(llist,7));

    Print_LinkList(llist);

    printf("线性链表的长度:%d\n",llist->data);

    printf("58的位置是:%d\n",SearchByData_LinkList(llist,58));

    ModifyByData_LinkList(llist,58,588);

    Print_LinkList(llist);

return EXIT_SUCCESS;

}










内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息