单链表相比数组的优势在于插入删除元素快,不需要移动大量的元素,只需要改变指针的指向,那么插入删除操作的时间复杂度应该是O(1),但是这是不对的,应该分情况讨论。
单链表结构体声明:
typedefstruct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
1. O(n)的情况:
1) 一个已知头结点的链表(假设足够长),删除第index个元素。
首先我们需要从头开始向后遍历,直到找到第index-1个结点,这需要O(n)时间;找到以后,改变指针的指向,这需要O(1)的时间。所以这种情况下,时间复杂度为O(n)。
代码:
LinkListhead;
LinkListp=head;
inti=0;
while(p&&i<=index-2)//找到第index-1个结点退出
{
p=p->next;
i++;
}
LinkListq=p->next;//q是第index个节点,即要删除的节点
p->next=q->next;//转移指针
free(q);//释放内存<pre name="code" class="cpp">LinkListnewnode=(LinkList)malloc(sizeof(LNode));
newnode->data=newdata;
newnode->next=node->next;
node->next=newnode;
q=NULL;//指向空指针
2) 一个已知头结点的链表(假设足够长),在第index个元素前插入一个元素。
首先我们需要从头开始向后遍历,直到找到第index-1个结点,这需要O(n)时间;找到以后,创建新节点,改变指针的指向,这需要O(1)的时间。所以这种情况下,时间复杂度为O(n)。
代码:
LinkList head;
LinkList p=head;
int i=0;
while(p&&i<=index-2)
{
p=p->next;
i++;
}
LinkList newnode=(LinkList)malloc(sizeof(LNode));
newnode->data=newdata;
newnode->next=p->next;
p->next=newnode;
2. O(1)的情况
1) 一个已知头结点的链表(假设足够长),删除某结点,且告诉你该元素的地址node(struct LNode*类型)。
由于这是单链表,我们无法获取node前一个节点的地址,因此好像不能删除这个结点。但是在我们看来,是否删除这个节点只是看这个节点的data值是否还存在于链表中,因此,我们可以让链表看起来删除了node,实则删除了结点node->next.
代码:
LinkListnode2=node->next;
node->data=node2->data;//移交元素
node->next=node2->next;//移交指针
free(node2);//释放目标删除结点后一个节点的内存
node2=NULL;//置空指针
这样,我们便“删除”了node结点,实则并没有删除,只是看起来删除了,实际上node->next成了真正的牺牲品。上述操作在O(1)内完成。
2) 一个已知头结点的链表(假设足够长),在某结点后面插入新节点,大小为newdata,且告诉你该结点的地址node(struct LNode *类型)。
代码:
LinkListnewnode=(LinkList)malloc(sizeof(LNode));
newnode->data=newdata;
newnode->next=node->next;
node->next=newnode;
上述操作O(1)时间内完成。