数据结构(c语言实现) !正在更新中...!

参考数据结构C语言版|第2版  严蔚敏

目录

第一章   绪论

1.1 数据结构研究的内容:数据结构主要研究非数值计算问题

1.2 基本概念和术语

1.2.1 数据、数据元素、数据项和数据对象

1.2.2 数据结构

1.3 抽象数据类型的表示和实现(无)

1.4 算法和算法分析

1.4.1 算法的定义和特性

1.4.2 评价算法优劣的基本标准

1.4.3 算法的时间复杂度

1.4.4 算法的空间复杂度

第二章   线性表

2.1 线性表的定义和特点

2.2 线性表的类型定义(无)

2.3线性表的顺序表示和实现

2.3.1 线性表的顺序存储表示

2.3.2 线性表的基本操作实现

2.4 线性表的链式存储表示与实现

2.4.1 单链表的定义和表示

2.4.2单链表基本操作的实现

2.4.3 循环链表

2.4.4 双向链表

2.5顺序表和链表的比较

2.5.1 空间性能比较

2.5.2 时间性能比较

2.6 线性表的应用

2.6.1 线性表的合并

2.6.2 有序表的合并

第三章 栈和队列

3.1 栈和队列的定义和特点

3.1.1 栈的定义和特点

3.1.2 队列的定义和特点

3.2 栈的表示和操作的实现

3.2.1 栈的类型定义

3.2.2 顺序栈的表示和实现

3.2.3 链栈的表示和实现

3.3 栈与递归

3.3.1 采用递归算法解决的问题

3.3.2 递归过程和递归工作栈

3.3.3 递归算法的效率分析

3.3.4 利用栈将递归转换为非递归的方法(空)

3.4 队列的表示和操作的实现

3.4.1 队列的类型定义

3.4.2 队列的顺序存储结构——循环队列

3.4.3 链队

第五章 树和二叉树

5.1 树和二叉树的定义

5.1.1 树的定义

5.1.2 树的基本术语

5.1.3 二叉树的定义

5.2 树和二叉树的抽象数据类型定义

5.3 二叉树的性质和存储结构

5.3.1 二叉树的性质

5.3.2 二叉树的存储结构

5.4 遍历二叉树和线索二叉树

5.4.1 遍历二叉树

5.4.2 线索二叉树

5.5 树和森林

5.5.1 树的存储结构

5.5.2 森林和二叉树的转换

5.5.3 树和森林的遍历

5.6 哈夫曼树及其应用

5.6.1 哈夫曼树的基本概念

5.6.2 哈夫曼树的构造算法

5.6.3 哈夫曼编码

第七章 查找

7.1 查找的基本概念

7.2 线性表的查找

7.2.1 顺序查找

7.2.2 折半查找

7.2.3 分块查找



预定义的常量及类型

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;           //为整型数据类型重新取一个名字为Status

//数据元素的类型约定为ElemType,由用户在使用时自行定义

理解:线性表,栈,队列,二叉树等的链式存储结构在定义其存储结构时,其实都是在定义它的结点类型,因为其是右许多这些结点构成的

第一章   绪论

1.1 数据结构研究的内容:数据结构主要研究非数值计算问题

1.2 基本概念和术语

1.2.1 数据、数据元素、数据项和数据对象

数据:客观事物的符号表示,是所有能输入到计算机中并被计算机程序处理的符号。

数据元素(记录,元素):数据的基本单位。如一条学生记录

数据项:组成数据元素的最小单位。如学生记录的某一个字段

数据对象:性质相同的数据元素的集合。

包含关系:数据>数据对象>数据元素>数据项

1.2.2 数据结构

数据结构是相互存在一种或多种特定关系的数据元素的集合。

一、数据结构有两个层次:逻辑结构和存储结构

1、数据的逻辑结构:描述数据元素间的逻辑关系,和存储无关。数据的逻辑结构有两个要素:一个是数据元素,二是关系。关系是数据元素间的逻辑关系

数据的逻辑结构通常有四类基本结构:

(1)集合结构:数据元素之间除了有属于同一集合的关系外,再无其他关系

(2)线性结构:数据元素之间存在一对一的关系

(3)树结构:数据元素之间存在一对多的关系

(4)图结构:数据元素之间存在多对多的关系

                                                         数据的逻辑结构分类

2、数据的存储结构:数据对象在计算机中的存储表示

数据元素在计算机中有两种基本的存储结构:分别是顺序存储结构和链式存储结构

(1)顺序存储结构:用一组地址连续的存储空间来存储元素,通常用程序设计语言的数组来表示。

(2)链式存储结构:为了表示结点间的关系,为每个结点附加指针,用于存放后继元素的地址,通常用程序设计语言的指针来表示。

1.2.3 数据类型和抽象数据类型(无)

1.3 抽象数据类型的表示和实现

抽象数据类型只是一个模型的定义,不涉及具体的实现

1.4 算法和算法分析

1.4.1 算法的定义和特性

算法:为了解决某类问题所规定的一个有限操作序列。

算法的五个特性:

(1)有穷性

(2)确定性

(3)可行性

(4)输入

(5)输出

1.4.2 评价算法优劣的基本标准

正确性:在合理的输入下能够在有限的时间内得到正确的结果

可读性:便于人们理解和交流

健壮性:能够对输入的错误数据进行相应的处理

高效性:包括时间和空间两个方面

1.4.3 算法的时间复杂度

1、问题规模和语句频度:问题规模是算法求解问题输入量的多少,问题大小的本质表示,一般用整数n来表示。一条语句重复执行的次数称为语句频度。

2、算法的时间复杂度定义

1.4.4 算法的空间复杂度

解决问题所需的额外空间

小结:要求掌握数据结构的相关基本概念,包括数据,数据元素,数据项,数据对象,数据结构,逻辑结构,存储结构等,重点掌握数据结构所含两个层次的具体含义和其相互关系,了解抽象数据类型的定义、表示与实现方法,了解算法的特性和评价标准,重点掌握算法时间复杂度的分析方法。

第二章   线性表

2.1 线性表的定义和特点

线性表:由n(n>=0)个数据特性相同的元素构成的有限序列。

说明:

线性表的长度:线性表中元素的个数;没有元素时称为空表。

对于非空线性表或线性结构,其特点是:

        (1)存在唯一一个被称作第一个的数据元素

        (2)存在唯一一个被称作最后一个的数据元素

        (3)除第一个数据元素之外,每个数据元素都只有一个直接前驱

        (4)除最后一个数据元素之外,每个数据元素均只有一个直接后继

2.2 线性表的抽象数据类型定义

2.3线性表的顺序表示和实现

2.3.1 线性表的顺序存储表示

线性表的顺序存储结构:一组地址连续的存储单元依次存储线性表中的数据元素。

  • 采用这种存储结构的线性表也称为顺序表。(特点:逻辑上相邻的数据元素,在物理次序也是相邻的)
//顺序表的顺序结构
#define MAXSIZE 100      //线性表的最大长度
typedef struct
{
    ElemType *elem;      //用一个指针来存储存储空间的基地址
    int length;          //表示顺序表的当前长度
}SqList;

2.3.2 线性表的基本操作实现

1.顺序表的初始化:构造一个空的顺序表。

算法步骤:①为线性表L动态分配一个预定义大小的数组空间,并让elem指向它。②将表的当前长度设置为0。

Status InitList(SqList &L)
{
    L.elem=new ElemType[MAXSIZE];   //动态分配一个预定义大小的数组空间给顺序表L
    if(!L.elem) exit(OVERFLOW);     //如果存储分配失败则退出
    L.length=0;                     //设置当前顺序表的长度为0
    return OK;
}

2.取值:按序号获取顺序表中数据元素的值

算法步骤:①先判断序号i是否合理(1<=i<=L.length),如果不合理,则返回ERROR。②如果i的值合理,就将第i个数据元素L.elem[i-1]赋值给参数e,通过e返回第i个数据元素的值。

Status GetElem(SqList L,int i,ElemType &e)
{
    if(i<1||i>L.length)return ERROR;
    e=L.elem[i-1];                  //第i个数据元素存储在elem[i-1]号存储单元中
    return OK;
}

3.查找:在顺序表中查找第一个与e相等的元素 

算法步骤:①从表中第一个元素开始,依次和e进行比较,如果查找到与e相等的数据元素,则查找成功,返回该元素的序号i+1(序号为1的元素存储在下标为0的数组空间中)。②如果整个表中都没有查找到e,则查找失败,返回0。

Status SearchElem(SqList L,ElemType e)
{
    for(int i=0;i<L.length;i++)  //从表中第一个元素开始,依次和e进行比较
    {
        if(L.elem[i]==e)return i+1;  //如果查找到,返回元素e在表中的序号
    }
    return 0;           //查找失败,返回0
}

4.插入:插入元素到顺序表中

算法步骤: ①先判断插入位置i是否合理(1<=i<=L.length+1),如果不合法则返回ERROR。②再判断顺序表的存储空间是否满了,满了则返回ERROR。③将最后一个元素到第i个位置的元素依次向后移动一个位置,腾出第i个位置(i=n+1时不需移动),将e插入到第i个位置上。④当前长度加1。

Status InsertList(SqList &L,int i,ElemType e)
{
    if((i<1)||(i>L.length+1)) return ERROR; //
    if(L.length==MAXSIZE) return ERROR;
    for(int j=L.length-1;j>=i-1;j--)
    {
        L.elem[j+1]=L.elem[j];
    }
    L.elem[i-1]=e;
    ++L.length;
    return OK;
}

5.删除:删除表中的第i个元素 

算法步骤:①先判断删除位置i是否合理(1<=i<=L.length),如果不合理则返回ERROR。②将第i+1个到最后一个元素依次往前移动一个位置(i=L.length的时候不用移动)③将线性表的当前长度减一。

Status ListDelete(SqList &L,int i)
{
    if((i<1)||(i>L.length)) return ERROR;  //插入位置不合理
    for(j=i;j<=L.length-1;j++)             
        L.elem[j-1]=L.elem[j];             //被删除元素之后的元素都往前移
    --L.length;
    return OK;
}
    

顺序表的优点:可以随机存取表中的任一元素

顺序表的缺点:①插入删除时要移动大量元素②浪费存储空间③数据元素的个数不能随意扩充 

2.4 线性表的链式存储表示与实现

2.4.1 单链表的定义和表示

单链表:由n个结点链接构成一个链表,每个结点由数据域和指针域组成。数据域是存储数据的域,指针域存储直接后继结点的地址。(因为每个结点只包含一个指针域所以叫做单链表或线性链表)

双链表:每个结点有两个指针域的链表

循环链表:首尾结点相接的链表

//----------线性表的链式存储结构(就是如何定义单链表的每个结点)
typedef struct LNode                  
{
    ElemType data;          //结点的数据域
    struct LNode *next      //结点的指针域
}LNode,*LinkList;

单链表的存取必须从头指针开始,头指针指向链表的第一个结点。

说明:  

(1)LNode和*LinkList本质上是等价的,习惯上用LinkList定义单链表(指向单链表的头指针) ,LNode定义指向结点的指针变量。例如:

LNode *p   
LinkList L   //L为单链表的头指针

(2)单链表是由表头指针唯一确定的,所以可以用头指针来命名单链表。

(3)注意区分指针变量和结点变量

LinkList p
LNode *p
//以上,p为指向某结点的指针变量,表示该结点的地址;
//而*p为对应的结点变量,表示该结点的名称

增加头结点的单链表:

首元结点、头结点、头指针说明:

(1)首元结点:存储链表中第一个数据元素a1的结点。

(2)头结点:是首元结点之前的一个结点。其指针域指向首元结点,数据域可以不存储任何信息,也可以存储和数据元素类型相同的其他信息。

(3)头指针:是指向链表的第一个结点的指针;分情况可指向头结点或首元结点

 

2.4.2单链表基本操作的实现

1.初始化:构造一个空表

算法:

①创建一个结点作为头结点,用头指针L指向头结点

②将头结点的指针域设置为空

Status InitList(LinkList &L)
{
    L=new LNode;      //创建一个新的结点为头结点
    L->next=NULL;    //将头结点的指针域置空
    return OK;
}

2.取值:根据结点的序号i,从链表的首元结点开始顺着链域next逐个结点向下访问 

算法:

①用结点类型的指针p指向首元结点,用j做计时器并设置初值为1

②从首元结点开始依次顺着链域next向下访问,只要指向当前结点的指针p不为空,且没有达到序号为i的结点时,进行以下循环:

        p指向下一个结点

        计数器j相应加1

③退出循环时,如果p指针为空,或计数器j大于i,则表示序号i不合法(i大于表长n或小于等于0),取值失败返回ERROR;否则取值成功,当i==j时,p指向的结点就是要查找的第i个结点,用参数e保存当前结点的数据域,返回OK

Status GetElem(LinkList L,int i,ElemType &e)
{
    p=L->next;
    j=1;
    while(p&&j<i)                //当p指向最后一个结点的后一个位置或p指向第i个元素
    {
        p=p->next;               //p指向下一个结点
        ++j;                    //计数器加1
    }
    if(!p||j>i)return ERROR;    //如果p为空或i不合法(i大于表长n或小于等于0),则返回ERROR
    e=p->data;
    return OK;
}
        
    

3.查找和顺序表类似,从链表的首元结点出发,依次将结点值和给定值e比较,返回查找结果

算法:

①用指针p指向首元结点

②从首元结点开始依次向下查找,指向当前结点的指针p不为空,并且p所指结点的数据域不等于e时,循环执行以下操作:

        p指向下一个结点

③返回p。如果查找成功,p此时为结点的地址值,若查找失败,p的值即为NULL

LNode *LocateElem(LinkList L,ElemType e)
{
    p=L->next;            //先用p指向首元结点
    while(p&&p->data!=e)
        p=p->next;
    return p;
}

4.插入:将 值e 插入到链表的第i个结点的位置上,即插入到ai-1和ai之间

算法:

①找到第i-1个结点并用指针p指向该结点

②创建一个新结点*s

③将新结点*s的数据域置为e

④将新结点*s的指针域指向第i个结点

 ⑤将结点*p的指针域指向新结点*s

Status ListInsert(LinkList &L,int i,ElemType e)
{
    p=L;
    j=0;
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值