学习数据结构从认识到单链表笔记

程序设计=数据结构+算法

数据:是描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合;
比如:我们常用的搜索引擎,网页,mp3,图片,视频等包括最重要的数组和字符文字数据;
我们这里说的数据,其实就是符号,而且这些符号必须具备前两个前提:
1.可以输入到计算机中;
2.能被计算机程序处理;


数据元素:是组成数据的,有一定意义的基本单位,在计算机中通常作为整体处理;也被称为记录;
比如:在人类中,什么是数据元素?人就是数据元素;


数据项:一个数据元素可以由若干个数据项组成;
比如:人这个数据元素,可以有眼镜,鼻子,耳朵,这些数据项,也可以有名字,生日,等数据项具体有哪些数据项,要视你做的系统来定;
数据项是数据不可分割的最小单位;


数据对象:是性质相同的数据元素的集合,是数据的子集;
比如:数据是生物类,数据对象是人类,数据元素就是某个人,数据项就是他的名字,生日等信息;


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


按照视点的不同数据分为逻辑结构和物理结构;
逻辑结构:是指数据对象中数据元素之间的相互关系;

逻辑结构分为四种:
1.集合结构:集合结构中数据元素除了同属一个集合外,它们之间没有其他关系;
2.线性结构:线性结构中的数据元素之间是一对一的关系;
3.树形结构:树形结构中的数据元素之间存在一种一对多的层次关系;
4.图形结构:图形结构的元素是多对多的关系;

物理结构:是指数据的逻辑结构在计算机中的存储形式;
1.顺序存储结构:是把元素存放在地址连续的存储单元里,其数据之间的逻辑关系和物理关系是一致的;
2.链式存储结构:是把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的;


数据类型:是指一组性质形同的值得集合及定义在此集合上的一些操作总称;
原子类型:是不可以在分解的基本类型,包括整形,实形,字符型等;
结构类型:由若干个类型组合而成,是可以在分解的。例如,整形数组是由若干整型数组成的;


抽象是指抽取出事物具有的普遍性的本质;


抽象数据类型:是指一个数学模型及定义在该模型上的一组操作;
抽象数据类型的定义取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关;
抽象的意义在于数据类型的数学抽象特性;
抽象数据类型体现了程序设计中问题分解,抽象和信息隐藏的特性;


                           数据
                              ↓
                        数据对象
                        ↓          ↓
            数据元素            数据元素
            ↓          ↓            ↓          ↓
    数据项1  数据项2    数据项1   数据项2

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


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


算法具有零个或多个输入;
算法至少有一个或多个输出,算法是一定需要输出的,不需要输出你用算法干吗?


有穷性:指算法在执行有限的步骤之后,自动结束而不会出现无限循环,并且每一个步骤在可接受的时间内完成;
现实中经常会写出死循环的代码,这就是不满足有穷性;
当然这里有穷的概念并不是纯数字意义的,而是在实际应用中合理的,可以接受的“有边界”;
一个算法计算机要算上二十年,一定会结束,它在数学意义上是有穷了,可是小姐姐都熬成老阿姨了,算法的意义也就不大了;

确定性:算法的每一步骤都具有确定的含义,不会出现二义性;
算法在一定条件下,只有一条执行路径,相同的输入只能有唯一的输出结果,算法的每个步骤被精确定义而无歧义;


可行性:算法的每一步都必须是可行的,也就是说,每一步都能够通过执行有限次数完成;
可行性意味着算法可以转换为程序上机运行,并得到正确的结果;

正确性:算法的正确性是指算法至少应该具有输入,输出和加工处理无歧义性,能正确反映问题的需求,能够得到问题的正确答案;
但是算法的正确通常在用算法上有很大的差别,大体分为以下四个层次:
1.算法程序没有语法错误;
2.算法程序对于合法输入数据能够产生满足要求的输出结果;
3.算法程序对于非法输入数据能够得出满足规格说明的结果;
4.算法程序对于精心选择的,甚至刁难的测试数据都有满足要求的输出结果;


可读性:算法设计的另一个目的是为了便于阅读,理解和交流;
可读性高,有助于人们理解算法,晦涩难懂的算法往往隐藏错误,不易发现,并且难于调试和修改;


健壮性:当输入数据不合法时,算法也能做出相关处理,而不是产生异常或莫名其妙的结果;


设计算法应该尽量满足时间效率高和存储量低的需求;


事后统计方法:这种方法主要是通过设计好的测试程序和数据,利用计算机计时器,对不同算法编制的程序的运行时间进行比较,从而确定算法效率的高低;


事前分析估算方法:在计算机程序编制前,依据统计方法对算法进行估算;
经过分析,我们发现,一个高级程序语言编写的程序在计算机上运行时所消耗的时间取决于下列因素:
1.算法采用的策略,方法;
2.编译产生的代码质量;
3.问题产生的输入规模;
4.机器执行指令的速度;


一个程序的运行时间,依赖于算法的好坏和问题的输入规模;
所谓问题输入规模是指输入量的多少;


最终,在分析程序的运行时间时,最重要的是吧程序看成是独立于程序设计语言的算法或一系列步骤;


函数的渐进增长:给定两个函数f(n)和g(n),如果存在一个整数N,使得对于所有的n>N,f(n)总是比g(n)大,
那么,我们说f(n)的增长渐进快于g(n);


我们可以忽略这些加法常数;

与最高次项相乘的常数并不重要;

最高次项的指数大的,函数随着n的增长特别快;


判断一个算法的效率时,函数中的常数和其他次要项常常可以忽略,而更应该关注主项(最高阶项)的阶数;


某个算法,随着n的增大,它会越来越优于另一个算法,或者越来越差于另一个算法;


算法时间复杂度定义
在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级;
算法的时间复杂度,也就是算法的时间量度,记作:T(n)=O(f(n));它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,
称作算法的渐进时间复杂度,简称为时间复杂度;其中f(n)是问题规模n的某个函数;


推导大O阶:
1.用常数1取代运行时间中的所有加法常数;
2.在修改后的运行次数函数中,只保留最高阶项;
3.如果最高阶项存在且不是1,则去除与这个项相乘的常数;
得到的结果就是大O阶;


分析算法的复杂度,关键就是要分析循环结构的运行情况;


理解大O推导不算难,难的是对数列的一些相关运算,这更多的是考察你的数学知识和能力;


最坏情况运行时间是一种保证,那就是运行时间将不会再坏了;在应用中,这是一种最重要的需求,除非特别指定,我们提到的运行时间都是最坏情况的运行时间;


平均运行时间是所有情况最有意义的,因为它是期望的运行时间;

一般在没有特殊说明的情况下,都是指最坏的时间复杂度;


算法的空间复杂度通过计算算法所需的储存空间实现,算法空间复杂的计算公式记作:S(n)=0(f(n)),其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数;


推导大O阶
用常数1取代运行时间中的所有加法常数;
在修改后的运行次数函数中,只保留最高阶项;
如果最高阶项存在且不是1,则去除与这个项相乘的常数;
得到的结果就是大O阶


线性表(List):零个或多个数据元素的有限序列;

线性表元素的个数n(n≥0)定义为线性表的长度,当n=0时,称为空表;


线性表的抽象数据类型定义如下:
ADT 线性表(List)
Data
      线性表的数据对象集合为{a1,a2,......,an},每个元素的类型均为DataType;
      其中,除第一个元素a1外,每一个元素有且只有一个直接前驱元素,除了最后一个元素an外,
      每一个元素有且只有一个直接后继元素;数据元素之间的关系是一对一的关系;
Operation
       InitList(*L):初始化操作,建立一个空的线性表L;
       ListEmpty(L) :若线性表为空,返回true,否则返回false;
       ClearList(*L)  :将线性表清空;
       GetElem(L,i,*e)  :将线性表L中的第i个位置元素值返回给e;
       LocateElem(L,e) :在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则,返回,0表示失败;
       ListInsert(*L,i,e):在线性表L中的第i个位置插入新元素e;
       ListDelete(*L,i,*e):删除线性表L中第i个位置元素,并用e返回其值;
       ListLength(L):返回线性表L的元素个数;
endADT


顺序存储定义:线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素;


一维数组来实现顺序存储结构


数据长度与线性表长度区别

这里有两个概念“数组的长度”和“线性表的长度”需要区分一下;
数组长度是存放线性表的存储空间的长度,存储分配后这个量是一般是不变的;
线性表的长度是线性表中数据的个数,随着线性表插入和删除操作的进行,这个量是变化的;
在任意时刻,线性表的长度应该小于等于数组的长度;


存储器中的每个存储单元都有自己的编号,这个编号称为地址;


插入算法的思路:
如果插入位置不合理,抛出异常;
如果线性表长度大于等于数组长度,则抛出异常或动态增加容量;
从最后一个元素开始向前遍历到第i个位置,分别将他们都向后移动一个位置;
将要插入元素填入位置i处;
表长加1


删除算法的思路:
如果删除位置不合理,抛出异常;
取出删除元素;
从删除元素位置开始遍历到最后一个元素位置,分别将他们都向前移动一个位置;
表长减1;


线性表顺序存储结构的优缺点
优点:1.无需为表示表中元素之间的逻辑关系而增加额外的存储空间;
          2.可以快速地存取表中任一位置的元素;
缺点:1.插入和删除操作需要移动大量元素;
          2.当线性表长度变化较大时,难以确定存储空间的容量;
          3.造成存储空间的“碎片”


链表中第一个终点的存储位置叫做头指针


在单链表的第一个终点前附设一个终点,称为头结点;


头指针与头结点的异同
头指针:1.头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针;   
             2.头指针具有标识作用,所以常用头指针冠以链表的名字
             3.无论链表是否为空,头指针均不为空;头指针是链表的必要元素;

头结点:1.头结点是为了操作的统一和方便而设立的,放在第一元素的终点之前,其数据域一般无意义
             2.有了头结点,对在第一元素终点前插入结点和删除第一终点,其操作与其他结点的操作就统一了;
             3.头结点不一定是链表必须要素;


对于插入或删除数据越频繁的操作,单链表的效率优势就越是明显


单链表整表创建的算法思路:
1.声明一结点p和计数变量i;
2.初始化一空链表L;
3.让L的头终点的指针指向NULL,及建立一个头结点的单链表;
4.循环;
    生成一新结点赋值给p;
    随机生成一数字赋值给p的数据域p->data;
    将p插入到头结点与前一新结点之间;

单链表整表删除的算法思路如下:
1.声明一终点p和q;
2.将第一个结点赋值给p;
3.循环;
   将下一结点赋值给q;
   释放p;
   将q赋值给p;


单链表结构与顺序存储结构优缺点
存储分配方式:
顺序存储结构用一段连续的存储单元依次存储线性表的数据元素;

单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素;


时间性能:
查找
   顺序存储结构O(1)
   单链表O(n)
插入和删除
    顺序存储结构需要平均移动表长一半的元素,时间为O(n)
    单链表在线出某位置的指针后,插入和删除时间仅为O(1)


空间性能:
   顺序存储结构需要预分配存储空间,分大了,浪费,分小了易发生上溢
   单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值