ALcohol_可豪 大一暑假算法与数据结构学习笔记
1 插入:链表增加元素,首部、中间和尾部分别会有什么问题,该如何处理?
先给出示例代码:
ListNode* ListNode::insertNode(ListNode* head, ListNode* nodeInsert,int position)
{
if(head == NULL)//如果是空链表,那么待插入的节点就是链表的头节点
return nodeInsert;
int size = getListLength(head);
if(position > size + 1 || position < 1)
{
cout<<"out of bound"<<endl;
return head;
}
//头插
if(position == 1)
{
nodeInsert->next = head;
head = nodeInsert;
return head;
}
ListNode* pre = head;
int count = 1;
while(count < position - 1)
{
pre = pre->next;
count++;
}
nodeInsert->next = pre->next;
pre->next = nodeInsert;
return head;
}
首先分析参数:head是指向头节点的指针,nodeInsert是待插入的指针,position是插入位置的后一个节点序号
对链表的数量进行分类,有空链表和非空链表
对于【空链表】,插入的节点就是链表的头节点,返回值也是头节点的指针。
if(head == NULL)
return nodeInsert;
考虑越界的情况
int size = getListLength(head);
if(position > size + 1|| position < 1) //@0
{cout<<"out of bound"<<endl; return head;}
@0:为什么position>size + 1是判定条件?
因为position的意义是待插入位置的后一个节点。
如果position=size+1,说明为尾插,即插入在链表屁股上。
对于【非空链表】,插入的节点又分为两种,一种是头插,即插入在所有链表之前,另一种是中间插入(包括中间和尾插)
对于头插,需要注意的是头插的判定,当position为1的时候判定为头插:
int size = getListLength(head);
if(position == 1)
nodeInsert->next = head;
head = nodeInsert;
return head;
对于中部插入和尾部插入,实际上是一样的。尾部插入可以看成是中部插入的一个特例。
首先需要找到链表插入位置的前一个节点。然后进行节点的连接。
ListNode* pre = head;
int count = 1;
while( count < position - 1 ) //@1
{
count++;
pre = pre->next;
}
@1:为什么下面是判定条件是( count < position - 1)
呢?
例如当postion为1时,插入位置为链表头,上面已经处理过了,这里不会出现position为1的情况;
而position为2时,count<position -1;直接判定为假,跳出循环,这个时候pre指向的就是head,而我们需要插入的位置,就是第position位置的前一个空挡,pre找到了position位置的前一个节点。
下面进行插入
nodeInsert->next = pre->next;
pre->next = nodeInsert;
return head;
为什么尾插被包括在上面了?
因为尾插入时,pre指向最后一个节点,pre->next == NULL
则nodeInsert->next = NULL;
逻辑正确
完成插入。
2 链表删除元素,首部、中间和尾部分别会有什么问题,该如何处理?
先给出示例代码
ListNode* ListNode::deleteNode(ListNode* head, int position)
{
if(head == NULL)
return NULL;
int size = getListLength(head);
if(size<1 || size>position)
{
cout<<"error of outBound"<<endl;
return head;
}
if(position == 1)
{
return head->next;
}
else
{
ListNode* pre = head;
int count = 1;
while(count<position-1)
{
pre = pre->next;
count++;
}
ListNode* cur = pre->next;
pre->next = cur->next;
}
}
先理解参数含义,head是头节点指针,position是待删除节点序号。返回值为删除后的头节点指针。
首先判断链表为空的情况
if(head == NULL)
return head;
如果链表不为空,判断待删除节点是否存在。
int size = getListLength(head);
if(position < 1 || position > size)
{cout<<"out of bound"<<endl; return head;}
如果position位置存在,下面开始删除
首先如果是头删,直接让头节点指向下一个节点即可
不用担心下一个节点是不是空,因为即便只有一个节点,删除后为空那么返回一个空链表也是符合逻辑的。
if(position == 1)
return head->next;
如果下一个链表是中间位置或者末尾
if(position == 1)
return head->next;
else
{
ListNode* pre = head;
int count = 1;
while(count < position -1 )
{
coun++;
pre = pre->next;
}
ListNode* cur = pre -> next;
pre->next = cur ->next;
}
return head;
这个和上面插入是相同的,找到待操作位置的前一个节点,然后执行操作。对于中间操作和尾部操作代码可以通用。
完成删除。