线性表
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素
线性表属性:
1、存储空间的起始位置:数组 data,它的存储位置就是存储空间的存储位置。
2、线性表的最大存储容量:数组长度MaxSize(线性表长度)
3、线性表的当前长度:length(数据长度)
线性表元素获取O(1):
获取数组指定下标的值
线性表插入元素O(n):
1、如果插入位置不合理,抛出异常;
2、如果线性表长度大于等于数组长度,则抛出异常或动态增加容量
3、从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置;
3、将要插入元素填入位置i处;
4、表长加1
线性表删除元素O(n):
1、如果删除位置不合理,抛出异常
2、取出删除元素
3、从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置
4、表长减1
线性表优缺点
单链表
为了表示每个数据元素Ai与其直接后继数据元素Ai+1之间的逻辑关系,对数据元素Ai来说,除了要存储自身的信息之外,还需蠢猪一个指示其直接后继的信息(即直接后继得到存储位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称做指针或链。这两部分信息组成数据元素Ai的存储映像,称为结点(Node)。
单链表查找 O(n)
1、声明一个结点p指向链表第一个结点,初始化 j从1开始;
2、. j<i 时,就遍历链表,让p的指针向后移动,不断指向下一结点, j累加1
3、若到链表末尾p为空,则说明第i个元素不存在
4、否则查找成功,返回结点p的数据
单链表插入O(n)
s->netx = p->next;
p->next = s;
上面两行代码的意思就是让p的后继结点变成s的后继结点,然后在把结点s变成p的后继结点。并且两行代码顺序不能改变,否则就会出现链表中断的情况。下面咋们来分析一下。加入代码变成这样:
p->next = s;
s->netx = p->next;
意思就是先把S变成p的后继结点,这没有问题,但是接着看下一行代码,把p的后继结点变成s的后继结点,因为上一行代码以及把s变成p的后继结点,所以这行代码的意思就变成了:
p->next = s;
s->netx = s;
s的后继结点指向了自己,所以后面的链表就断了。切记两行代码顺序不能改变。
单链表的删除O(n)
p->next =p->next->next
用q来代替p->next
q=p->next(中间结点)
p->next = q->next
上面这段代码的意思其实就是让p的后继结点直接指向p的后继结点的后继结点,所以q结点就被孤立了。
总结
从整个算法来说,我们很容易推导出:它们的时间复杂度都是 O(n) 。如果在我们
不知道第i个元素的指针位置,单链表数据结构在插入和删除操作上,与线性表的顺
序存储结构是没有太大优势的。但如果,我们希望从第i个位置,插入10个元素,对
于顺序存储结构意味着,每一次插入都需要移动n-i个元素,每次都是 O(n) 。而单
链表,我们只需要在第一次时,找到第i个位置的指针,此时为 O(n),接下来只是简
单地通过赋值移动指针而已,时间复杂度都是 0(1) 。显然 ,对于插入或删除数据越频繁的操作,单链表的效率优势就越是明显。
对比
静态链表(通过数组模拟链表)
例子:
此时"甲"这里就存有下一元素"乙 的游标2 ,"乙"则存有下一元素"丁'的下标 3。而"庚"是最后一个有值元素,所以它的 cur 设置为 0。而最后一个元素的cur 则因"甲'是第一有值元素而存有它的下标为1.而第一个元素则因空闲空间的第一个元素下标为 7,所以它的 cur 存有7。
总的来说,静态链表其实是为了给没有指针的高级语言设计的一种实现单链袭能
力的方法。尽管大家不一定会用得上,但这样的思考方式是非常巧妙的,应该理解其
思想,以备不时之需。
循环链表
把为指针指向头结点地址
循环链表合并
p=rearA->next;
rearA->next = rearB->next->next;
rearB->next=p;
free(p);
双向链表
由于这是双向链表,那么对于链表中的某一个结点p,它的后继的前驱是谁?当然还是它自己。它的前驱的后继自然也是它自己,即:
p->next->prior = p = p->prior->next
双向链表插入
s -> prior = p;
s->next = p->next;
p->next->prior = s;
p->next = s;
关键在于它们的顺序,由于第2步和第3步都用到了 p->next。如果第4步先执行,则会使得 p->next 提前变成了s,使得插入的作完不成。所以我们不妨把上面这张图在理解的基础上记忆,顺序是先搞定s的前驱和后继,再搞定后结点的前驱,最后解决前结点的后继。
双向链表删除
p->prior->next = p->next;
p->next->prior = p->prior;
free(p)