第二章:线性表(顺序表VS链表)
在 学习数据结构–第二章:线性表(顺序存储、插入、删除)
和
学习数据结构–第二章:线性表(链式存储、单链表、双链表、循环链表) 这两篇文章中分别讲了顺序表和链表的存储特点以及基本的操作,下面讲解顺序表和链表的一些区别和在解决实际问题的时候我们应该做出怎样的选择,以及线性表的常用操作。
1.顺序表和链表的差异性
在单链表中每一个数据的存储不一定是连续的,所以我们无法实现随机存取,只能通过指针连接各个结点,所以我们只能实现顺序存取。
而在顺序表中每一个数据源的存放是连续的,我们只需要通过LOC(A)+(n-1)*sizeof(ElemType)这个式子,只要我们知道第一个元素的地址,我们就可以通过计算得到每一个元素的地址,这样就可以实现随机存取和顺序存取。故:
单链表:只能实现顺序存取
。
顺序表:可以实现顺序存储
和随机存取
。
2.逻辑结构和物理结构差异性
单链表中数据元素的存储位置是任意的,可能相邻也可能不相邻,而顺序表元素的存储位置一定是相邻的。
链表是通过指向下一个元素的指针来维持逻辑结构的,每一个元素不仅存放了数据元素还存放了下一个数据元素的地址,通过指针将所有的元素穿成一个链。而顺序表是通过数据元素的相邻性来维持逻辑结构的,在逻辑上相邻的数据元素,在物理上也是相邻的。
顺序表:逻辑相邻物理上也相邻
,通过相邻
表示逻辑关机。
单链表:逻辑相邻物理上不一定相邻
,通过指针
表示逻辑关系。
3.线性表的基本操作
3.1插入
顺序表中:元素向后移动->将新元素赋值
单链表中:新结点S的next指针指向p结点的后一个结点->修改p结点的next指针指向新的结点S。
3.2删除
顺序表中:将要删除的元素开始,将后面的元素依次向前移动。
单链表中:首先一个新的指针指向将要删除的结点q—>接着修改q的前面一个结点的next指针指向q后面的的结点—>接着释放q结点的空间。
插入&删除
- 单链表为
O(1)
(节点指针已知);O(n)
(节点指针未知),但操作时只需修改指针 - 顺序表为
O(n)且需要大量移动元素
3.3查找
按值查找
顺序表中:遍历整个顺序表对比值。O(n)
单链表中:遍历整个单链表对比值。O(n)
按序号查找
顺序表中:按照序号,我们通过数组的下标既可以直接找到对应序号的数组元素的位置。O(1)
单链表中:需要遍历整个链表。O(n)
查找
- 按值查找中单链表和顺序表(
无序
)都为O(n); - 按序查找中单链表为O(n),顺序表为O(1);
3.内存空间的差异性
顺序存储 无论静态分配还是非静态都需要预先分配
合适的内存空间静态分配时预分配空间太大回造成浪费,太小会造成溢出;动态分配时虽不会溢出但是扩充需要大量移动元素,操作效率低
链式存储 在需要时分配
结点空间即可,高效方便,但指针要使用额外空间。
4.怎样选择线性表的存储结构?
5.线性表的常用操作
5.1求最值
顺序表
首先使用两个变量标记数组的第一个元素为最大值和最小值,接着遍历顺序表,如果该元素大于最大值,则修改最大值的变量,如果小于最小值,则修改最小值变量。遍历结束即可得到最大值和最小值。
时间复杂度:O(n)
int min=L[0];
int max=L[0];
for(int i=0;i<n;i++){
if(min>L[i]){
min=L[i];
}
if(max<L[i]){
max=L[i];
}
}
单链表
同理和顺序表。
时间复杂度:O(n)
5.2求逆置
顺序表
思路一,我们申请一个辅助空间,然后从尾部到头遍历整个顺序表,然后将每一个元素插入到新的空间中即可,但是这样的时间和空间复杂度是O(n)。下面讲解另一种方法:
我们可以使用两个标记分别指向头部元素i
和尾部元素j
的值,接着交换两个标记的数据元素的值,然后将i
标记向后移动一位,j
标记向前移动一位,继续交换元素的值…直到i<j
的时候结束。这种方法的时间复杂度为O(n),空间复杂度为O(1)
单链表
在单链表中我们有一个头指针(p
)和尾指针(r
),我们将第一个数据元素结点移动到(r)
指针后面,接着继续将第一个数据元素结点移动到(r
)指针后面…持续操作,直到p
指针的下一个结点为(r
)结点结束。
代码讲解:
p->next!=r
就是移动结束的判断条件,移动到r
结点作为第一个结点的时候结束。temp=p->next
是保存p
结点的下一个结点。p->next=temp->next
就是直接将p结点和temp后面的结点相连接
。【前两个语句是将要移动的结点拿出去并保存】temp->next=r->next
修改要插入的结点的next指针指向r
结点的后一个结点,r->next=temp;
就是连接起来。【后两个语句是连接操作】
时间复杂度:O(n).
5.3合并
顺序表
需要新申请一个空间,大小为两个顺序表空间的和,然后需要找到两个书顺序表中元素值最小的那个,然后插入的新的表中。这时需要借助三个标记,一个(i
)指向L1的第一个位置,一个(j
)指向L2的第一个位置,一个(k
)指向新数组,注意这里的顺序表的元素都是从小到大排列的,我们只需要保证合并后的元素值也是从小到大排列。
然后我们需要一次比较两个数组的元素的值,如果L1[i]<L2[i],这时将L1[i]添加到新的的数组中,同时标记k++,然后让i++,j不变,然后继续比较,如果L1数组的元素比较完了,此时L2数组还有剩余,此时不需要比较了,直接将L2数组元素依次添加到新数组中即可。
其中
i<L1_Size&&j<L2_Size
就是判断两个数组是否全部移除。下面的两个while
判断就是判断两个数组是否全部移除完毕,因为不知道那个数组没移除完毕。
时间复杂度:O(n)
单链表
基本同理顺序表。