数据结构基础

学习目标:


学习内容:

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

逻辑结构
集合,所有数据在同一个集合中,关系平等。
线性,数据和数据之间是一对一的关系
树, 一对多
图,多对多

物理结构(在内存当中的存储关系)
顺序存储,数据存放在连续的存储单位中。逻辑关系和物理关系一致
链式,数据存放的存储单位是随机或任意的,可以连续也可以不连续。
struct Per 数据元素
{
char name;//数据项
int age;
char phone;
}

struct Per list[100]; //数据对象

数据的类型,ADT    abstruct datatype 
是指一组性质相同的值的集合及定义在此集合上的一些操作的总称。
原子类型,int,char,float
结构类型,sturct, union,

抽象数据类型, 数学模型 + 操作。

程序 =  数据 + 算法

算法,
是解决特定问题求解步骤的描述,计算机中表现为指令的有限序列,每条指令表示一个或多个操作。


算法的特征,
1,输入,输出特性,输入时可选的,输出时必须的。
2,有穷性,执行的步骤会自动结束,不能是死循环,并且每一步是在可以接受的时间内完成。
3,确定性,同一个输入,会得到唯一的输出。
4,可行性,每一个步骤都是可以实现的。


算法的设计,
1,正确性,
语法正确
合法的输入能得到合理的结果。
对非法的输入,给出满足要求的规格说明
对精心选择,甚至刁难的测试都能正常运行,结果正确
2,可读性,便于交流,阅读,理解
3,健壮性,输入非法数据,能进行相应的处理,而不是产生异常
4,高效,存储低,效率高 
crc

fn()
{


for(i)
{
i=i*3;
}
}

2n
O(n)


一个例子,1~ 100 求和。。。
100 = n 
fn()
{
for()        n
{
for()        n
{
for()        n
{
sum= sum+i;n
}
}
}

for(int i= 0 ;i<100;i++)        n 201
{
sum= sum+i;n   2*100
}    n*2+1 +2n  = 4n+1
sum= sum+i;n
sum= sum+i;n
sum= sum+i;n
}
10


O(n)
n^3   O(n^3) 


int i ,sum; //8 
for(10000)    n
{
sum = i+sum; 2n +3
}
a = c;
b =c;
a = d;


O(n) int n ; 4
n = (n+1)*n/2  4
O(1)

1 2 3 4 5 .....95 96 97 98 99 100 

从这里看以看出算法的优劣,好坏




for(100)
{}
for(100)
{}
a+=a; 1
b+=a;1 
c +=a;1


2n+3,    O(n)
3n+1;
4n+8 ,2n^2 +10;
2n^2+3n+1, 2n^3+3n+1; 
2n^2,3n+1,2n^2+3n+1;



1

算法时间复杂度
也就是执行这个算法所花时间的度量
n  1  = O(n)   O(1)
推到时间复杂度
1,用常数1 取代运行时间中的所有加法常数
2,在修改后的运行函数中,只保留最高阶项。
3,如果最高阶存在且不是1,则取除这个项相乘的常数。

for(i=0;i<n;i++)
{
i=5*i;
}

for()n
{
for()n
}
O(1)<O(logn)<O(N)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)



for(int i = 0 ;i<100; i = *5)
{

}

线性表
零个或多个数据元素的有限序列
元素之间是有顺序了。如果存在多个元素,第一个元素无前驱,最有一个没有后继,其他的元素只有一个前驱和一个后继。
当线性表元素的个数n(n>=0)定义为线性表的长度,当n=0时,为空表。在非空的表中每个元素都有一个确定的位置,如果a1是第一个元素,那么an就是第n个元素。

线性表的常规操作  ADT
typedef struct person {
char name[32];
char sex;
int age;
int score;
}DATATYPE;
typedef int Datatype;
typedef struct list {
DATATYPE *head;
int tlen;
int clen;
}SeqList;

SeqList *CreateSeqList(int len);
int DestroySeqList(SeqList *list);
int ShowSeqList(SeqList *list);
int InsertTailSeqList(SeqList *list, DATATYPE data);
int IsFullSeqList(SeqList *list);
int IsEmptySeqList(SeqList *list);
int InsertPosSeqList(SeqList *list, DATATYPE data, int pos);
int FindSeqList(SeqList *list, char *name);
int ModifySeqList(SeqList *list, char *old, DATATYPE new);
int DeleteSeqList(SeqList *list, char *name);
int ClearSeqList(SeqList *list);
内存泄露检测工具
sudo apt-get install valgrind
valgrind ./all

char buf[1024];

线性表顺序存储的优点,缺点
优点
1,无需为表中的逻辑关系增加额外的存储空间
2,可以快速随机访问元素O(1)
缺点
1,插入,删除元素需要移动元素o(n)
2,无法动态存储。
 

线性表的链式存储
解决顺序存储的缺点,插入和删除,动态存储问题。
特点:
,线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素,存储单元可以是连续的,也可以不连续。可以被存储在任意内存未被占用的位置上。

所以前面的顺序表只需要存储数据元素信息就可以了。在链式结构中还需要一个元素存储下一个元素的地址。

为了表示每个数据元素,ai与其直接后继数据元素ai+1之间的逻辑关系,对ai来说,除了存储其本身的信息外,还需要存一个指示器直接后续的信息。把存储元素信息的域叫数据域,把存储直接后继位置的域叫指针域。这两部分信息组成数据元素ai的存储映像,叫结点(Node);



单链表中,c语言的描述
typedef struct person {
char name[32];
char sex;
int age;
int score;
}DATATYPE;

typedef struct node {
DATATYPE data;
struct node *next,*prev;
}LinkNode;

typedef struct list {
LinkNode *head;
int tlen;
int clen;
}LinkList;

LinkList *CreateLinkList(int len);
int InsertHeadLinkList(LinkList *list, DATATYPE data);
int ShowLinkList(LinkList *list);
LinkNode *FindLinkList(LinkList *list, char *name);
int DeleteLinkList(LinkList *list, char *name);
int ReviseLinkList(LinkList *list, char *name, DATATYPE data);
int DestroyLinkList(LinkList *list);
int InsertTailLinkList(LinkList *list, DATATYPE data);



顺序表和链表 优缺点
存储方式:
顺序表是一段连续的存储单元
链表是逻辑结构连续物理结构(在内存中的表现形式)不连续
时间性能,
查找 顺序表O(1)
 链表  O(n)
插入和删除
顺序表 O(n)
链表   O(1)

空间性能
顺序表 需要预先分配空间,大小固定
链表, 不需要预先分配,大小可变,动态分配


循环链表
简单的来说,就是将原来单链表中最有一个元素的next指针指向第一个元素或头结点,链表就成了一个环,头尾相连,就成了循环链表。circultlar linker list.

注意非空表,和空表。多数会加入头结点。
原来结束的条件是
p->next != NULL ------->>>>> p-next != Head 

双向链表
double link list。

typedef struct DulNode
{

ElemType date;
struct DulNode *pri;
sturct DulNode *next;
}DulNode,*DuLinkList;
 

栈:   3+5*6
栈是限定仅在表尾进行插入和删除操作的线性表。
先进后出、后进先出


栈顶:允许操作的一端
栈底:不允许操作的一端
入栈,出栈。
顺序栈 链式栈
30+2\5
1.创建 CreateSeqStack
2.销毁 DestroySeqStack
3.判断是否为空栈 IsEmptySeqStack
4.判断是否为满栈 IsFullSeqStack
5.压栈 PushSeqStack
6.出栈 PopSeqStack


队列:
队列是只允许在一段进行插入,而在另一端进行删除操作的线性表。
允许插入的称谓队尾,允许删除的一端队头。
顺序队列。
循环队列,
常用操作,入队,出队。
先进先出,FIFO
#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <errno.h>

#define error_exit(_errmsg_) error(EXIT_FAILURE, errno, _errmsg_)
typedef int DATATYPE;
typedef struct queue {
DATATYPE *ptr;
int tlen;
int head;
int tail;
}SeqQueue;

int DestroySeqQueue(SeqQueue *queue);
DATATYPE QuitSeqQueue(SeqQueue *queue);
int EnterSeqQueue(SeqQueue *queue, DATATYPE data);
int IsEmptySeqQueue(SeqQueue *queue);
int IsFullSeqQueue(SeqQueue *queue);
SeqQueue *CreateSeqQueue(int len);

#endif



#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <errno.h>

#define error_exit(_errmsg_) error(EXIT_FAILURE, errno, _errmsg_)

typedef int DATATYPE;

typedef struct node {
DATATYPE data;
struct node *next;
}QueueNode;

typedef struct queue {
QueueNode *head;
int tlen;
int clen;
QueueNode *tail;
}LinkQueue;
int DestroyLinkQueue(LinkQueue *queue);
DATATYPE QuitLinkQueue(LinkQueue *queue);
int EnterLinkQueue(LinkQueue *queue, DATATYPE data);
int IsFullLinkQueue(LinkQueue *queue);
int IsEmptyLinkQueue(LinkQueue *queue);
LinkQueue *CreateLinkQueue(int len)
;
#endif


树:n(n>=0)个结点的有限集合。n = 0 ,空树。
在任意一个非空树中,
1,有且仅有一个特定的根结点
2,当n>1 时,其余结点可分为m个互不相交的有限集合T1,T2,T3.。。。。Tm,其中每一个
集合又是一个树,并且称谓子树。


结点拥有子树的个数称谓结点的度。度为0的结点称谓叶结点。度不为0,称谓分支结点。

树的度数是指,这棵树中,最大的结点的度数,称谓树的度数。
树的深度或高度,从根开始,根为第一层,根的孩子为第二层。

树的存储,顺序结构,链式结构。


二叉树,binary tree
n个结点的有限集合,集合要么为空树,要么由一个根结点和两棵互不相交,分别称谓根结点的左子树和右子树的二叉树组成。。

特点,
1,每个结点最多两个子树。
2,左子树和右子树是有顺序的,次序不能颠倒。
3,如果某个结点只有一个子树,也要区分左,右子树。

特殊的二叉树
1,斜树,所有的结点都只有左子树,左斜树,所有结点都只有右子树,右树。
2,满二叉树,所有的分支结点都存在左右子树,并且叶子都在同一层上。
3,完全二叉树,对于一颗有n个结点的二叉树按层序编号,如果编号i(1<=i<=n)的结点于同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这可树为完全二叉树。

特性
1,在二叉树的第i层上最多有2^(i-1)个结点 i>=1
2,深度为k的二叉树至多有2^k  -1 个结点 k>=1
3,任意一个二叉树T,如果其叶子结点的个数是n0,度数为2的结点数为n2, n0 = n2 +1;
4,有n个结点的完全二叉树深度为(logn/log 2) +1;

层序,
前序,根左右,先访问根,然访问左,访问右。
中序,左根右,先从根开始(不是先访问根),从左开始访问,在访问根,在访问右结点。
后序,左右根,先从根开始(不是先访问根),先访问左,在访问右。在访问根。

typedef struct BiTNode  /* 结点结构 */
{
   TElemType data; /* 结点数据 */
   struct BiTNode *lchild,*rchild; /* 左右孩子指针 */
}BiTNode,*BiTree;

CreateBiTree();
DestroyBiTree();

PreOrderTraverse();
void InOrderTraverse(BiTree T);
void PostOrderTraverse(BiTree T);


学习产出:

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值