顺序表
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。
静态顺序表:使用固定长度的数组存储元素
动态顺序表:使用动态开辟的数组存储
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空
间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间
大小。
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDateType;
//顺序表的动态存储
typedef struct SeqList
{
SLDateType* array;//指向动态开辟的数组
int size;//有效数据的个数
int capacity;//容量空间的大小
}SeqList;
//基本的增删查改接口
//顺序表的初始化
void SeqListInit(SeqList* psl)
{
assert(psl);
psl->array = (SLDateType*)malloc(sizeof(SLDateType)*4);
if (psl->array == NULL)
{
perror("malloc fail");
return;
}
psl->size = 0;
psl->capacity = 4;
}
void CheckCapacity(SeqList* psl)
{
assert(psl);
if (psl->size == psl->capacity)
{
SLDateType* tmp = (SLDateType*)realloc(psl->array, sizeof(SLDateType) * psl->capacity * 2);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
psl->array = tmp;
psl->capacity *= 2;
}
}
//顺序表的尾插
void SeqListPushBack(SeqList* psl, SLDateType x)
{
assert(psl);
CheckCapacity(psl);
psl->array[psl->size] = x;
psl->size++;
}
//顺序表的尾删
void SeqListPopBack(SeqList* psl)
{
assert(psl);
assert(psl->size > 0);
psl->size--;
}
//顺序表的头插
void SeqListPushFront(SeqList* psl,SLDateType x)
{
assert(psl);
CheckCapacity(psl);
int end = psl->size-1;
while (end>=0)
{
psl->array[end+1] = psl->array[end];
end--;
}
psl->array[0] = x;
psl->size++;
}
//顺序表的头删
void SeqListPopFront(SeqList* psl)
{
assert(psl);
assert(psl->size > 0);
int start = 0;
while (start<psl->size-1)
{
psl->array[start] = psl->array[start + 1];
start++;
}
psl->size--;
}
//顺序表的查找
int SeqListFind(SeqList* psl, SLDateType x)
{
assert(psl);
int i = psl->size;
int start = 0;
while (i--)
{
if (psl->array[start] == x)
{
return start;
}
start++;
}
return -1;
}
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDateType x)
{
assert(psl);
assert(0 <= pos && pos <= psl->size);
CheckCapacity(psl);
int i = psl->size - pos;
int end = psl->size-1;
while (i--)
{
psl->array[end + 1] = psl->array[end];
end--;
}
psl->array[pos] = x;
psl->size++;
}
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos)
{
assert(psl);
assert(psl->size > 0);
assert(0 <= pos && pos < psl->size);
int start = pos + 1;
int i = psl->size - pos-1;
while (i--)
{
psl->array[start - 1] = psl->array[start];
start++;
}
psl->size--;
}
// 顺序表销毁
void SeqListDestory(SeqList* psl)
{
assert(psl);
free(psl->array);
psl->array = NULL;
psl->capacity = 0;
psl->size = 0;
}
// 顺序表打印
void SeqListPrint(SeqList* psl)
{
assert(psl);
int i = psl->size;
int start = 0;
while (i--)
{
printf("%d ", psl->array[start]);
start++;
}
printf("\n");
}
#include "test.h"
void TestSeqList1()
{
SeqList s;
SeqListInit(&s);
SeqListPushBack(&s, 1);
SeqListPushBack(&s, 2);
SeqListPushBack(&s, 3);
SeqListPushBack(&s, 4);
SeqListPushBack(&s, 5);
SeqListPushBack(&s, 6);
SeqListPushBack(&s, 6);
SeqListPushBack(&s, 6);
SeqListPushBack(&s, 6);
SeqListPrint(&s);
SeqListDestory(&s);
}
void TestSeqList2()
{
SeqList s;
SeqListInit(&s);
SeqListPushBack(&s, 1);
SeqListPushBack(&s, 2);
SeqListPushBack(&s, 3);
SeqListPushBack(&s, 4);
SeqListPushFront(&s, 5);
SeqListPushFront(&s, 6);
SeqListPushFront(&s, 6);
SeqListPushFront(&s, 7);
SeqListPushFront(&s, 6);
SeqListPrint(&s);
SeqListDestory(&s);
}
void TestSeqList3()
{
SeqList s;
SeqListInit(&s);
SeqListPushBack(&s, 1);
SeqListPushBack(&s, 2);
SeqListPushBack(&s, 3);
SeqListPushBack(&s, 4);
SeqListPushFront(&s, 5);
SeqListPushFront(&s, 6);
SeqListPrint(&s);
SeqListPopBack(&s);
SeqListPopBack(&s);
SeqListPrint(&s);
SeqListPopBack(&s);
SeqListPopBack(&s);
SeqListPrint(&s);
SeqListPopBack(&s);
SeqListPopBack(&s);
//SeqListPopBack(&s);
SeqListPrint(&s);
SeqListPushBack(&s, 1);
SeqListPushBack(&s, 2);
SeqListPushBack(&s, 3);
SeqListPushBack(&s, 4);
SeqListPrint(&s);
SeqListDestory(&s);
}
void TestSeqList4()
{
SeqList s;
SeqListInit(&s);
SeqListPushBack(&s, 1);
SeqListPushBack(&s, 2);
SeqListPushBack(&s, 3);
SeqListPushBack(&s, 4);
SeqListPrint(&s);
SeqListPopFront(&s);
SeqListPopFront(&s);
SeqListPrint(&s);
SeqListPopFront(&s);
SeqListPopFront(&s);
SeqListPrint(&s);
//SLPopFront(&s);
//SLPopFront(&s);
//SLPrint(&s);
SeqListDestory(&s);
}
void TestSeqList5()
{
SeqList s;
SeqListInit(&s);
SeqListPushBack(&s, 1);
SeqListPushBack(&s, 2);
SeqListPushBack(&s, 3);
SeqListPushBack(&s, 4);
SeqListPushBack(&s, 5);
SeqListPushBack(&s, 6);
SeqListPrint(&s);
SeqListInsert(&s, 2, 30);
SeqListPrint(&s);
//SLInsert(&s, 20, 30);
//SLPrint(&s);
//SLInsert(&s, -20, 30);
//SLPrint(&s);
SeqListErase(&s, 3);
SeqListPrint(&s);
SeqListPopFront(&s);
SeqListPrint(&s);
SeqListPopBack(&s);
SeqListPrint(&s);
SeqListDestory(&s);
}
//
void TestSeqList6()
{
SeqList s;
SeqListInit(&s);
SeqListPushBack(&s, 1);
SeqListPushBack(&s, 2);
SeqListPushBack(&s, 3);
SeqListPushBack(&s, 4);
SeqListPushBack(&s, 5);
SeqListPushBack(&s, 6);
SeqListPrint(&s);
int pos = SeqListFind(&s, 6);
if (pos != -1)
{
SeqListErase(&s, pos);
}
SeqListPrint(&s);
SeqListDestory(&s);
}
void TestSeqList7()
{
SeqList* s = NULL;
SeqListPushBack(s, 1);
SeqListPushBack(s, 2);
SeqListPushBack(s, 3);
SeqListPrint(s);
SeqListDestory(s);
}
int main()
{
//TestSeqList1();
/*TestSeqList2();*/
//TestSeqList3();
/*TestSeqList4();*/
/*TestSeqList5();*/
/*TestSeqList6();*/
TestSeqList7();
return 0;
}
顺序表笔试题
原地移除数组中所有的元素val,要求时间复杂度为O(N),空间复杂度为O(1)。
//快慢指针,找到val值之前一直++,找到之后拷贝一起++
int removeElement(int* nums, int numsSize, int val)
{
int prev=0;
int cur=0;
while(cur<numsSize)
{
if(nums[cur]==val)
{
cur++;
}
else
{
nums[prev++]=nums[cur++];
}
}
return prev;
}
//快慢指针,相同++,不同跳一个位置再拷贝,然后一起++
int removeDuplicates(int* nums, int numsSize)
{
int src=1;
int dst=0;
while(src<numsSize)
{
if(nums[src]==nums[dst])
{
src++;
}
else
{
dst++;
nums[dst]=nums[src];
src++;
}
}
return dst+1;
}
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
int end1=m-1;
int end2=n-1;
int i=m+n-1;
while(end1>=0 && end2>=0)
{
if(nums1[end1]>nums2[end2])
{
nums1[i--]=nums1[end1--];
}
else
{
nums1[i--]=nums2[end2--];
}
}
while(end2>=0)
{
nums1[i--]=nums2[end2--];
}
}
链表
单链表
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLTDateType;
typedef struct SListNode
{
struct SListNode* next;
SLTDateType date;
}SListNode;
// 动态申请一个结点
SListNode* BuySListNode(SLTDateType x)
{
SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
if (tmp == NULL)
{
perror("malloc fail");
return NULL;
}
tmp->date = x;
tmp->next = NULL;
return tmp;
}
// 单链表打印
void SListPrint(SListNode* plist)
{
SListNode* cur = plist;
while (cur)
{
printf("%d->", cur->date);
cur = cur->next;
}
printf("NULL\n");
}
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
if (*pplist==NULL)
{
*pplist = BuySListNode(x);
}
else
{
SListNode* tail = *pplist;
while (tail->next!=NULL)
{
tail = tail->next;
}
tail->next = BuySListNode(x);
}
}
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
SListNode* newnode = BuySListNode(x);
if (*pplist == NULL)
{
*pplist = newnode;
}
else
{
SListNode* next = *pplist;
newnode->next = next;
*pplist = newnode;
}
}
// 单链表的尾删
void SListPopBack(SListNode** pplist)
{
assert(*pplist!=NULL);
SListNode* tail = *pplist;
if (tail->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
}
// 单链表头删
void SListPopFront(SListNode** pplist)
{
assert(*pplist);
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SListNode* next = (*pplist)->next;
free(*pplist);
*pplist = next;
}
}
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
SListNode* cur = plist;
while (cur)
{
if (cur->date == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
// 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* newnode = BuySListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
//单链表在pos位置之前插入x
void SListInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{
assert(pphead);
assert(pos);
if (*pphead = pos)
{
SListPushFront(pphead, x);
}
else
{
SListNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
SListNode* newnode = BuySListNode(x);
prev->next = newnode;
newnode->next = pos;
}
}
//单链表在pos位置之后删除
void SListEraseAfter(SListNode* pos)
{
assert(pos);
assert(pos->next);
SListNode* next = pos->next;
pos->next = next->next;
free(pos->next);
}
// 删除pos位置的值
void SListErase(SListNode** pphead, SListNode* pos)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
SListPopFront(pphead);
}
else
{
SListNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
}
}
笔试题
//cur遍历,prev存储要找的前一个结点的地址
//节点是要找的,将cur的next地址给prev的next,释放cur,再将prev的next给cur往后走,注意第一个节点就是要找的时候特殊处理,将head的next给cur,释放旧头head,将新头cur给head
//节点不是要找的,将cur给prev,cur往后走
struct ListNode* removeElements(struct ListNode* head, int val)
{
struct ListNode* cur=head;
struct ListNode* prev=NULL;
while(cur)
{
if(cur->val==val)
{
if(prev)
{
prev->next=cur->next;
free(cur);
cur=prev->next;
}
else
{
cur=head->next;
free(head);
head=cur;
}
}
else
{
prev=cur;
cur=cur->next;
}
}
return head;
}
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* cur=head;
struct ListNode* rhead=NULL;
while(cur)
{
struct ListNode* next=cur->next;
//头插
cur->next=rhead;
rhead=cur;
//迭代
cur=next;
}
return rhead;
}
//思路一:快慢指针,slow走一步,fast走两步
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* pre=head;
struct ListNode* cur=head;
while(cur&&cur->next)
{
pre=pre->next;
cur=cur->next->next;
}
return pre;
}
//思路二:count计数
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* cur=head;
struct ListNode* prev=head;
int count=0;
while(cur)
{
cur=cur->next;
count++;
}
count/=2;
while(count--)
{
prev=prev->next;
}
return prev;
}
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
struct ListNode* cur1=list1;
struct ListNode* cur2=list2;
struct ListNode* newhead=NULL;
struct ListNode* next=NULL;
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
while(cur1&&cur2)
{
if(cur1->val<cur2->val)
{
if(newhead)
{
next->next=cur1;
next=cur1;
cur1=cur1->next;
}
else
{
newhead=next=cur1;
cur1=cur1->next;
}
}
else
{
if(newhead)
{
next->next=cur2;
next=cur2;
cur2=cur2->next;
}
else
{
newhead=next=cur2;
cur2=cur2->next;
}
}
}
if(cur1==NULL)
{
next->next=cur2;
}
if(cur2==NULL)
{
next->next=cur1;
}
return newhead;
}
//两个链表两个哨兵位,小的尾插第一个,大的尾插第二个,然后将其链接起来,注意malloc的两个哨兵位要free,两链表链接时要注意head2的位置,还有就是tail2的next要为NULL
class Partition {
public:
ListNode* partition(ListNode* pHead, int x)
{
ListNode* cur=pHead;
ListNode* head1=NULL;
ListNode* tail1=NULL;
ListNode* head2=NULL;
ListNode* tail2=NULL;
head1=tail1=(ListNode*)malloc(sizeof(ListNode));
head2=tail2=(ListNode*)malloc(sizeof(ListNode));
while(cur)
{
if(cur->val<x)
{
tail1->next=cur;
tail1=cur;
cur=cur->next;
}
else
{
tail2->next=cur;
tail2=cur;
cur=cur->next;
}
}
tail1->next=head2->next;
tail2->next=NULL;
ListNode* newhead=head1->next;
free(head1);
head1=NULL;
free(head2);
head2=NULL;
return newhead;
}
};
//这题算是综合题,首先找到中间节点,然后将中间节点之后的节点进行逆置,然后进行比对
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* cur=head;
struct ListNode* rhead=NULL;
while(cur)
{
struct ListNode* next=cur->next;
cur->next=rhead;
rhead=cur;
cur=next;
}
return rhead;
}
class PalindromeList {
public:
bool chkPalindrome(ListNode* A)
{
struct ListNode* mid=middleNode(A);
struct ListNode* rhead=reverseList(mid);
while(rhead)
{
if(A->val!=rhead->val)
{
return false;
}
A=A->next;
rhead=rhead->next;
}
return true;
}
};
//相交链表的尾节点一定相同,其次长的链表先走差距步,然后一起走,节点的地址相同就相交
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
struct ListNode* cur1=headA;
struct ListNode* cur2=headB;
int count1=0;
int count2=0;
while(cur1)
{
count1++;
cur1=cur1->next;
}
while(cur2)
{
count2++;
cur2=cur2->next;
}
if(cur1!=cur2)
{
return NULL;
}
int gas=abs(count1-count2);
struct ListNode* lesslist=headA;
struct ListNode* greatlist=headB;
if(count1>count2)
{
lesslist=headB;
greatlist=headA;
}
while(gas--)
{
greatlist=greatlist->next;
}
while(lesslist&&greatlist)
{
if(lesslist==greatlist)
{
return lesslist;
}
lesslist=lesslist->next;
greatlist=greatlist->next;
}
return NULL;
}
//slow走一步,fast走两步,如果有环必定就有相等的时候
bool hasCycle(struct ListNode *head)
{
struct ListNode* slow=head;
struct ListNode* fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
return true;
}
}
return false;
}
有关环型链表的思考:
slow和fast为什么一定会相遇?一定会相遇
解释:fast会先进环,slow会后进环,假设slow进环时,slow和fast之间的距离为N
slow进环以后,fast追击slow,他们距离的变化为:
N
N-1
N-2
N-3
…
2
1
0
等于0的时候是恰好追上
只能是slow走一步,fast走两步?不是,只是fast和slow相差一步是一定会相遇
假设slow走一步,fast走三步,距离就是2为单位减少
那么N为偶数时候距离变化:
N N-2 N-4 N-6 … 4 2 0,所以也是恰好追上
N为奇数时距离变化:
N N-2 N-4 N-6 … 3 1 -1,这一轮就错过了,开始下一轮的追击,假设环的长度C
此时slow和fast的距离变成C-1,如果说C-1是偶数,那就变成了第一种情况,在这一轮恰好追上
如果说C-1是奇数,那这一轮又是第二种情况而且永无止境的是第二种情况,也就永远也追不上了
环形链表 II
环形链表 II
//一个指针从相遇点走,一个指针从链表头开始走,他们会在入口点相遇
struct ListNode *detectCycle(struct ListNode *head)
{
struct ListNode* slow=head;
struct ListNode* fast=head;
struct ListNode* ring=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
while(ring!=slow)
{
ring=ring->next;
slow=slow->next;
}
return ring;
}
}
return NULL;
}
证明:一个指针从相遇点走,一个指针从链表头开始走,他们会在入口点相遇
slow一次走一步,fast一次走两步
假设链表头到环入口点的距离:L
环入口点到相遇点的距离是:X
环的长度是:C
slow走的路程是:L+X(slow一圈之内,fast必然追上slow,因为每次距离减一,不会错过)
fast走的路程是:L+nC+X(n为slow进环前,fast在环里面转的圈数)
2*(L+X)=L+nC+X
L=n*C-X 或者 L=(n-1)*C+C-X
将(n-1)*C所转的圈数去掉,就是L=C-X
故证明成立
//1.拷贝节点插入到源节点的后面
//2.控制拷贝节点的random
//3.拷贝节点截下来尾插组成拷贝链表,恢复源链表
struct Node* copyRandomList(struct Node* head)
{
struct Node* cur=head;
while(cur)
{
struct Node* copy=(struct Node*)malloc(sizeof(struct Node));
copy->val=cur->val;
struct Node* next=cur->next;
cur->next=copy;
copy->next=next;
cur=next;
}
cur=head;
while(cur)
{
struct Node* copy=cur->next;
if(cur->random==NULL)
{
copy->random=NULL;
}
else
{
copy->random=cur->random->next;
}
cur=copy->next;
}
struct Node* copyhead=NULL;
struct Node* copytail=NULL;
cur=head;
while(cur)
{
struct Node* copy=cur->next;
struct Node* next=copy->next;
if(copytail)
{
copytail->next=copy;
copytail=copytail->next;
}
else
{
copyhead=copytail=copy;
}
cur->next=next;
cur=next;
}
return copyhead;
}
带头双向链表的实现
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* prev;
struct ListNode* next;
}LTNode;
//链表开辟节点
LTNode* BuyLTNode(LTDataType x)
{
LTNode* temp = (LTNode*)malloc(sizeof(LTNode));
if (temp == NULL)
{
perror("malloc fail");
return NULL;
}
temp->data=x;
temp->prev = NULL;
temp->next = NULL;
return temp;
}
//链表初始化
LTNode* Init()
{
LTNode* phead = BuyLTNode(-1);
phead->next = phead;
phead->prev = phead;
return phead;
}
//链表的打印
void LTPrint(LTNode* phead)
{
assert(phead);
printf("guard<==>");
LTNode* cur = phead->next;
while (cur!=phead)
{
printf("%d<==>", cur->data);
cur = cur->next;
}
printf("\n");
}
//判断链表是否为空
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;
}
//链表尾插
void LTPushBack(LTNode* phead,LTDataType x)
{
assert(phead);
//LTInsert(phead, x);
LTNode* tail = phead->prev;
LTNode* newnode = BuyLTNode(x);
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
//链表的头插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* first = phead->next;
LTNode* newnode = BuyLTNode(x);
newnode->next = first;
first->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
}
//链表的头删
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* second = phead->next->next;
free(phead->next);
phead->next = second;
second->prev = phead;
}
//链表的尾删
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
//LTErase(phead->prev);
LTNode* tail = phead->prev;
LTNode* tailPrev = tail->prev;
free(tail);
tailPrev->next = phead;
phead->prev = tailPrev;
}
//链表的查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
//在pos之前插入
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* prev = pos->prev;
LTNode* newnode = BuyLTNode(x);
prev->next = newnode;
newnode->prev = prev;
pos->prev = newnode;
newnode->next = pos;
}
//删除pos位置的值
void LTErase(LTNode* pos)
{
assert(pos);
assert(!LTEmpty(pos));
LTNode* posPrev = pos->prev;
LTNode* posNext = pos->next;
posPrev->next = posNext;
posNext->prev = posPrev;
free(pos);
pos = NULL;
}
//销毁链表
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
顺序表和链表的优缺点
链表优点:
1.任意位置插入删除O(1)
2.按需申请释放空间
缺点:
1.不支持下标的随机访问
2.CPU高速缓存命中率会更低(就是说在访问一个地址的时候,会加载附近的内存,而链表的空间是随机分配的,所以说命中率会更低)
顺序表优点:
1.尾插尾删效率高
2.下标的随机访问
3.CPU高速缓存命中率会更高
缺点:
1.前面部分插入删除数据,效率是O(N),需要挪动数据
2.空间不够,需要扩容(扩容需要付出代价,一般还会伴随空间浪费)