数据结构与算法回炉重造 -- (三)

版权声明:本文为博主原创文章,未经博主允许可以转载。(转呀转呀/笑哭),希望标注出处hhh https://blog.csdn.net/qq_36428171/article/details/88390955

线性表

由零个或者多个数据元素组成的有限序列,每个元素最多只有一个前驱和后继。

List的抽象数据类型定义:

  • ADT 线性表(List)
  • Data 数据
  • Operation 操作
InitList(*L)//初始化
ListEmpty(L)//判断是否为空表
//增删改查
ClearList(*L)//将线性表清空
GetElem(L,i,*e)//将线性表i位置元素返回给e

线性表的顺序存储结构

需要封装三个属性:

  • 存储空间的起始位置
  • 最大存储容量
  • 线性表当前长度

查找算法时间复杂度为O(1)
增删改的算发时间复杂度为O(n)

线性表的链式存储结构

单链表:

第一个节点存储位置叫做头结点,最后一个结点指针为空
头指针存在于头结点,链表必须存在头指针,在每一个节点中,存储数据和指向下一个节点的指针
C语言描述:

typedef struct Node{
	ElemType data;
	struct Node *Next;
} Node;

建立单链表:
1、头插法建立无头节点单链表
2、尾插法建立单链表

单链表的整表删除:
从头结点开始逐个删除

查找链表第i个数据:
需要声明指向头结点的指针p,通过移动p到i位置,得到链表数据
所以时间复杂度为O(n)
增删改只需要通过指针的修改也是O(n)
但是相对于顺序结构存储,增删改操作越是频繁,单链表结构更具有优势,查找操作越多,顺序表更具有优势。

题目:快速找到未知长度单链表的中间节点

普通方法:遍历单链表确定长度L,再遍历找到L/2处节点的位置 O(3L/2)
优化:快慢指针(标尺思想)
设置两个指针,慢指针步长为1,快指针步长为2 ,当快指针到达链表尾部,慢指针就到达中间节点
O(L/2)

判断单链表是否有环
方法一:通过两个指针p,q,q以步长为1遍历到链表尾,q每移动一个位,更新q移动的距离Q,p遍历到q指针的位置,并得到p指针移动的距离P,如果P!=Q,那么单链表有环。

方法二:通过快慢指针,q每次走一步,p每次走两步,p每走一步都进行判断,如果p==q了,那么就意味着有环。

静态链表

利用数组代替指针建立游标,存放下一节点数据的位置
通常数据数组的第一个和最后一个元素不存放数据,未使用的数据数组称之为备用链表。
数据数组已存放数据的最后一个元素的游标为0
游标第一个元素存放备用链表的第一个节点下标
游标最后一个元素存放第一个有数值元素的下标,相当于单链表的头结点。

其思想极为巧妙

循环链表

将单链表的尾部节点的由空指针指向头结点,循环链表和单链表的主要区别是空表的判断,单链表判断头指针下一元素是不是等于null,循环链表则是判断是不是等于头指针。

问题: 用循环链表模拟约瑟夫问题。

双向链表

将单链表节点再增加一个前驱节点,就形成了双向链表。
C语言描述:

typedef struct DualNode{
	ElemType data;
	struct DualNode *prior;
	struct DualNode *next;
}

双向链表即时牺牲空间换取时间。

猜你喜欢

转载自blog.csdn.net/qq_36428171/article/details/88390955