单链表
LeetCode上的定义:
struct ListNode 单链表的结构体
{
int val; 节点值
ListNode *next; 节点下一个地址
ListNode(int x):val(x),next(NULL){}; 构造函数
};
从头到尾打印单链表
思路:
1.由于递归相当于是堆栈结构,后进先出。因此可以考虑不停调用函数进行递归。递归结束的条件为IF(HEAD==NULL)。此时返回一次指针就指向单链表的最后一个元素上,开始执行打印操作即可;
2.对单链表进行遍历,将节点内的值存入堆栈中。
3.对单链表进行遍历,将节点内的值存入VECTOR中,利用STL的REVERSE()函数对VECTOR容器进行反转;
4.参见1.3单链表就地反转。
代码1:
vector<int> vec;
vector<int> printListFromTailToHead(ListNode* head)
{
if(head==NULL)
return vec;
vec=printListFromTailToHead(head->next);
vec.push_back(head->val);
return vec;
}
代码2:
vector<int> vec;
vector<int> printListFromTailToHead(ListNode* head)
{
if(head==NULL)
return vec;
while(head)
{
vec.push_back(head->val);
head=head->next;
}
reverse(vec.begin(),vec.end());
return vec;
}
找到单链表中点(倒数第N个点)
思路:
这种题目可以从数组角度去考虑,但是这样就意味着需要先搜索一般得到单链表的长度,再利用类似数组的方式去搜索某个特定位置的数,时间复杂度较高。对于这种搜索特定位置的题目,可以依靠两个指针(快慢指针)来进行。此时则最多仅需遍历一次单链表。
寻找单链表中点:设置两个指针(快慢指针),快指针每次走两步,慢指针每次走一步。当快指针走到头时,慢指针刚好在中点的位置。(这里是偶数个时中点选择靠右边的那个)
代码段:
ListNode* findMidNode(ListNode* head)
{
ListNode *slow, *fast;
slow = head;
fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
寻找单链表倒数第N个点:设置快慢指针,快指针先走N步,然后一起出发速度相同。当快指针走到头时,慢指针刚好在倒数第N个位置。
代码段:
ListNode* findMidNode(ListNode* head)
{
ListNode *slow, *fast;
slow = head;
fast = head;
for(int i=1;i<N;++i)
{
if (fast->next!=NULL)
{
throw new Exception("单链表元素个数小于 "+n+" !");
}
fast = fast->next;
}
while (fast->next)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
单链表原地反转
即不改变节点内部值和不增加额外链表就地实现整张链表的反转,其辅助空间复杂度为O(1)。
思路:
头插法:包含有头结点!!逆置链表初始为空,表中节点从原链表中依次“删除”,再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的第一个结点,如此循环,直至原链表为空。
代码:
void converse (ListNode *head)
{
ListNode *p,*q;
if(head==NULL||head->next==NULL) //如果头结点后没有元素或者仅有一个元素,则无需反转。
return
p=head->next;
head->next=NULL;
while(p)
{
/*向后挪动一个位置*/
q=p;
p=p->next;
/*头插*/
q->next=head->next;
head->next<