链表

单向链表:查找第i个结点时只能从头结点开始,复杂度为O(n)。

题目:链表的创建,结点插入,删除结点,反转链表,倒数第k个结点...

1.向链表的尾部插入结点

typedef struct ListNode{int m_nvalue;ListNode* m_pNext;};
//往链表末尾中添加节点
void AddToTail(ListNode** pHead,int value)     //特别注意pHead是一个指向指针的指针。因为往空链表中插入一个结点时,头指针是新插入的结点。此时头指针发生了改动,因此必须设置为指向指针的指针,否则出了该函数之后pHead仍然是一个空指针
{
    ListNode *pNew=new ListNode();
    pNew->m_nvalue=value;
    pNew->m_pNext=NULL;
    if(*pHead==NULL)   
    {
        *pHead=pNew;
    }
    else                              
    {
        ListNode* pNode=*pHead;
        while(pNode->m_pNext!=NULL)
            pNode=pNode->m_pNext;
        pNode->m_pNext=pNew;
    }
}

2.删除结点

可以在O(1)复杂度下删除结点,最坏情况(删除的是尾结点)复杂度为O(n)。

//在链表中找到第一个含有某值的结点,并删除它。(只能从头向尾遍历,算法复杂度O(n),不能像数组那样采用索引)
void RemoveNode(ListNode**pHead,int value)
{
    if(pHead==NULL||*pHead==NULL)     //*pHead==NULL表示空表  phead==NULL表示该指针未定义
        return;
    ListNode* ToBeDeleted=NULL;
    if((*pHead)->m_nvalue==value)  //如果头指针所指向的结点就是要删除的结点,则把头指针指向下一个结点,把头结点赋值为要被删除的点ToBeDeleted
    {
        ToBeDeleted=*pHead;          
        *pHead=(*pHead)->m_pNext;
    }
    else                          //否则就去判断下一个结点是否应该被删除
    {
        ListNode* pNode=*pHead;
        while(pNode->m_pNext!=NULL&&pNode->m_pNext->m_nvalue!=value)   //下一个结点不是要删除的结点,继续往后移动
        {
            pNode=pNode->m_pNext;
        }
        if(pNode->m_pNext!=NULL&&pNode->m_pNext->m_nvalue==value)    //否则把下一个结点赋值为ToBeDeleted
        {
            ToBeDeleted=pNode->m_pNext;
            pNode->m_pNext=pNode->m_pNext->m_pNext;     //当前结点的指针指向下一个结点的下一个结点
        }
    }
    if(ToBeDeleted!=NULL)                 //找到了应该删除的结点时就删掉,否则结束寻找
    {
        delete ToBeDeleted;
        ToBeDeleted=NULL;
    }
}
//在O(1)时间之内删除链表结点
void DeleteNode(ListNode** pListHead,ListNode* pToBeDeleted)
{
    if(!pListHead||!pToBeDeleted)
        return;
    //要删除的不是尾结点。如果要删除的是结点i,
    if(pToBeDeleted->m_pnext!=NULL)
    {
        ListNode* pNext=pToBeDeleted->m_pnext;
        pToBeDeleted->m_key=pNext->m_key;
        pToBeDeleted->m_pnext=pNext->m_pnext;
        delete pNext;
        pNext=NULL;
    }
    //链表只有一个结点,删除头结点
    else if(*pListHead==pToBeDeleted)
    {
        delete pToBeDeleted;
        pToBeDeleted=NULL;
        *pListHead=NULL;
    }
    //链表中有多个结点,删除尾结点
    {
        ListNode* pNode=*pListHead;
        while(pNode->m_pnext!=pToBeDeleted)
        {
            pNode=pNode->m_pnext;
        }
        pNode->m_pnext=NULL;
        delete pToBeDeleted;
        pToBeDeleted=NULL;
    }
}

3.从尾到头打印结点,不改变链表结构

//从尾到头打印链表,不改变链表结构
void PrintListReverse(ListNode**pHead)
{
    if(pHead==NULL||*pHead==NULL)
        return;
    ListNode* pNode=*pHead;
    vector<int> v_list;
    v_list.insert(v_list.begin(),pNode->m_nvalue);
    while(pNode->m_pNext!=NULL)
    {
        pNode=pNode->m_pNext;
        v_list.insert(v_list.begin(),pNode->m_nvalue);
    }
    vector<int>::iterator it=v_list.begin();
    while(it!=v_list.end())     //对的
        printf("%d ",*it++);
    /*while(it++!=v_list.end())   //这样写是从第2个数开始输出,并且指针溢出了。只有在for循环里面才保证循环体内的语句执行完了之后再自增,在while的判断里面是判断语句执行完了就自增。
        printf("%d ",*it);*/
    /*while(it++!=v_list.end())     //这样写是从第2个数开始输出,指针没有溢出。
        printf("%d ",*it);*/
}

4.链表结构的反转

//链表结构的反转
void ListReverse(ListNode**pHead)
{
    if(pHead==NULL||*pHead==NULL||(*pHead)->m_pNext==NULL)
        return;
    ListNode* p=*pHead;
    ListNode* q=*pHead;
    while(p->m_pNext!=NULL)
    {
        *pHead=p->m_pNext;
        p->m_pNext=(*pHead)->m_pNext;
        (*pHead)->m_pNext=q;
        q=*pHead;
    }
}
void main()
{
    ListNode** pHead=new ListNode*;    //不赋值,就会出现指针未初始化的错误.原因是指针未赋值时,其值并不是0,而是随便指向了一处内存,当改变了此处内存的值时,可能会带来灾难性的错误
    *pHead=NULL;
    int print_value,remove_value;
    for(int i=0;i<7;i++)
    {
        cin>>print_value;
        AddToTail(pHead,print_value);
    }
    PrintListReverse(pHead);
    cin>>remove_value;
    RemoveNode(pHead,remove_value);
    ListReverse(pHead);
    PrintListReverse(pHead);
}

 5.面试题:找到两个链表的第一个公共结点——剑指offer面试题37

思路1:用2个栈存储两个链表,从栈顶开始比较,相同的移除,移除的最后一个相同的结点就是两个链表的第一个公共结点。

思路2:首先分别遍历两个链表的长度,求得长度差k。设置2个指针,较长链表的指针先行k步,然后比较2个指针的值是否相同,如果不同,2个指针同时后移,直到找到第一个相同的指针为止。

思路1的代码:

//输入两个链表,找到他们第一个公共结点
#include<stdlib.h>
#include<stdio.h>
#include<stack>
#include<iostream>
using namespace std;

struct ListNode
{
    int m_key;
    ListNode* m_pnext;
};

ListNode* findPublic(ListNode* const list1,ListNode* const list2)   //指针值不能变   如果写成const ListNode* ,代表的是元素值不能变
{
    ListNode* PublicNode=new ListNode;
    if(list1==NULL||list2==NULL)
        return NULL;     //这样写行吗?
    ListNode* plist1,*plist2;
    plist1=list1;    //不能将const ListNode*分配到ListNode*类型的实体
    plist2=list2;
    stack<ListNode*> stack1,stack2;
    while(plist1!=NULL)                  //把链表压栈
    {
        stack1.push(plist1);
        plist1=plist1->m_pnext;
    }
    while(plist2!=NULL)
    {
        stack2.push(plist2);
        plist2=plist2->m_pnext;
    }
    while(stack1.top()==stack2.top())    //反过来比较,直到找到最后一个重合的值为止
    {
        PublicNode=stack1.top();
        stack1.pop();
        stack2.pop();
    }
    return PublicNode;
}

//生成一个链表的写法
void inputList(ListNode* &pfirst)    //初始化时,要写成ListNode* pfirst=NULL
{
    int p;
    ListNode* currentNode=NULL;
    while(cin>>p)
    {
        if(p==-1)
            break;
        ListNode* newNode=new ListNode;
        newNode->m_key=p;
        newNode->m_pnext=NULL;
        if(pfirst==NULL)               
        {
            pfirst=newNode;
            currentNode=pfirst;
        }
        else
        {
            currentNode->m_pnext=newNode;
            currentNode=currentNode->m_pnext;
        }
    }
}

 6.合并2个排序的链表——剑指offer面试题17

//合并2个排序的链表
ListNode* Merge(ListNode* pHead1,ListNode* pHead2)
{
    if(pHead1==NULL)
        return pHead2;
    else if(pHead2==NULL)
        return pHead1;
    ListNode* pMergedHead=NULL;
    if(pHead1->m_key<pHead2->m_key)
    {
        pMergedHead=pHead1;
        pMergedHead->m_pnext=Merge(pHead1->m_pnext,pHead2);
    }
    else
    {
        pMergedHead=pHead2;
        pMergedHead->m_pnext=Merge(pHead1,pHead2->m_pnext);
    }
    return pMergedHead;
}

 

posted @ 2015-07-21 23:09  wy1290939507  阅读(244)  评论(0编辑  收藏  举报