反转链表和查找倒数第K个节点

来源:互联网 发布:.co.jp 日本域名 编辑:程序博客网 时间:2024/06/14 10:07

一:链表的逆置(反转链表)
题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后的头结点:
节点的结构

struct ListNode{    ListNode(const int& val)    :_val(val)    ,next(NULL)    {}    int _val;    ListNode*next;};

这里写图片描述

这里面我们需要三个指针分别是cur,用来顺序遍历整个链表,newhead指针用来保存逆置的头结点,prev用来逆序遍历链表.
步骤:
1:先遍历整个链表找到当前节点的下一个节点为空,即为尾节点也是逆置后的头结点
2:prev用来保存当前节点的上一个节点.
3:然后更新节点的位置,把当前节点指针指向前一个节点,再把它的下一个指针指向当前位置,这样就可以保证所有节点链在一起了.

ListNode*ReverseList(ListNode*phead){  ListNode *cur =phead;  ListNode*newhead=NULL;   ListNode*prev =NULL;    while(cur!=NULL)    {        ListNode*_next = cur->next;        if(_next ==NULL)        newhead =cur;//找到逆置后的头结点        cur->next =prev;//保存上一个节点      //更新当前节点的位置        prev = cur;        cur =_next;    }    return newhead;}

二:查找倒数第k个节点
题目:输入一个链表,数除该链表的倒数第K个节点.
常规的思路是从尾到头开始遍历,然后就可以找到第k个节点,但是我们忽略了一个前提的条件就是这个链表时单向链表,不能从后先前遍历,因此这种方法行不通

既然从尾到头不能遍历我们还是从头遍历,那么如何找到倒数第k个节点呢?我们先假设链表有n个节点,那么倒数第K个节点就是从开始向后走n-k+1(n>k)步就好了,如何得到节点数n,遍历链表每遍历一个,计数器加1;
查找倒数第K个节点我们就要遍历遍历两次事件复杂度就是N^2,那么如何只遍历一次事件复杂度是0(N)呢?
方法:快慢指针
这里写图片描述
我们仔细分析下,
第一步:开始的时候假设快慢指针都指向首位置,
第二步:让快指针先走k-1步,慢指针不动,
第三步:快慢指针同时走,当快指针走两步的之后刚好到达链表的尾,而,慢指针走两步刚好到达K(值为3)的位置.
这样就可以实现查找倒数第k个目的.

ListNode *FindKthToTail(ListNode*phead,unsigned int k){//首先要判断头结点是否为空,以及k是否有效    if(phead ==NULL||k ==0)    return NULL;    ListNode*fast=phead;    ListNode*slow =phead;    for(unsigned i =0;i<k-1;i++)    {   //满足k小于结点的总数        if(fast->next ==NULL)        {            return NULL;        }        else{      fast =fast->next;       }    }    while(fast->next!=NULL)    {        fast =fast->next;        slow =slow->next;    }    return slow;}

三:验证:(C++实现)

#include<iostream>#include<stdlib.h>using namespace std;struct ListNode{    ListNode(const int& val)    :_val(val)    ,next(NULL)    {}    int _val;    ListNode*next;};//逆置单链表ListNode*ReverseList(ListNode*phead){  ListNode *cur =phead;  ListNode*newhead=NULL;   ListNode*prev =NULL;    while(cur!=NULL)    {        ListNode*_next = cur->next;        if(_next ==NULL)        newhead =cur;        cur->next =prev;        prev = cur;        cur =_next;    }    return newhead;}//查找倒数第K个节点ListNode *FindNKToTail(ListNode*phead,unsigned int k){    if(phead ==NULL||k<0)    return NULL;    ListNode*fast=phead;    ListNode*slow =phead;    for(int i =1;i<k;i++)    {        if(fast->next ==NULL)        {            return NULL;        }        else{      fast =fast->next;        }     // fast =fast->next;    }    while(fast!=NULL&&fast->next!=NULL)    {        fast =fast->next;        slow =slow->next;    }    return slow;}//添加节点ListNode* BuyNode(int x){    ListNode*node = (ListNode*)malloc(sizeof(ListNode));    node->_val = x;    node->next = NULL;    return node;}//打印单链表void PrintList(ListNode*phead){    ListNode*cur = phead;    while(cur)    {        cout<<cur->_val<<"->";        cur =cur->next;    }    cout<<endl;}//创建单链表ListNode*CreatList(){    ListNode*head;    ListNode*node1 = BuyNode(1);    ListNode*node2 = BuyNode(2);    ListNode*node3 = BuyNode(3);    head=node1;    node1->next =node2;    node2->next =node3;    node3->next =NULL;    return node1;}void Test(){    cout<<"before"<<endl;    ListNode*head =CreatList();    PrintList(head);  //  cout<<"after"<<endl;   // ListNode*newhead =ReverseList(head);   // PrintList(newhead);    cout<<"查找倒数第K个节点"<<endl;    ListNode*newhead1 =FindNKToTail(head,2);    PrintList(newhead1);}

四: 实现一个Add函数,让两个数相加,但是不能使用+、-、*、/等四则运算符。ps:也不能用++、–等等
//位运算完成+,-

int add(int a,int b){ int c;    while(c =(a&b))    {        a =a^b;        b= (c<<1);    }    return (a^b);}//减法,a取反再加1int sub(int a){   add(a,b);    return add(~a,1);}int main(){    int a =-1;    int b =-2;    add(a,b);    sub(a);    cout<<add(a,b)<<endl;    cout<<sub(a)<<endl;      Test();      return 0;}
原创粉丝点击