您的位置:首页 > 其它

链表的常见操作

2013-09-16 21:22 183 查看
链表是数据结构的重要内容,在计算机程序中应用广泛,同时也是各公司笔试题目的重点。

  以下简单实现了链表的一些操作,包括创建、增加节点、删除节点、单链表逆置、合并有序链表等。



一、链表创建

  链表主要有三种形式,包括单链表、双链表和循环链表。

  单链表每个节点只包含一个后驱指针,双链表节点同时包含一个前驱指针和一个后驱指针,循环链表的尾节点的后驱指向头节点。

  代码如下:





/*单链表节点结构*/
typedef struct NodeType
{
    char elem;
    NodeType *next;
}Node;

/*双链表节点结构*/
typedef struct DNodeType
{
    char elem;
    DNodeType *next;
    DNodeType *prev;
}DNode;














/*
创建链表
*/
Node * CreateList(Node *head)
{
    if(NULL == head)//分配头节点空间
        head=(Node*)malloc(sizeof(Node)),
        head->next=NULL;

    Node *current=head , *temp;
    char ch;

    while(1)
    {
        cout<<"\n input elem:";
        cin>>ch;
        if('#' == ch)            /*#结束输入*/
            break;
        temp=(Node *) malloc ( sizeof(Node) );
        temp->elem=ch;
        temp->next=NULL;
        current->next=temp;        /*当前节点的后驱指向新节点*/
        current=temp;            /*当前节点为链表尾节点*/

    }

    return head;
}










/*创建双链表*/
DNode * DoubleList(DNode *head)
{
    if(NULL == head)//分配头节点空间
        head=(DNode*)malloc(sizeof(DNode)) , head->prev=NULL , head->next=NULL;
        

    DNode *current=head , *temp;
    char ch;

    while(1)
    {
        cout<<"\n input elem:";
        cin>>ch;
        if('#' == ch)           /*#结束输入*/
            break;
        temp=(DNode *) malloc ( sizeof(DNode) );
        temp->elem=ch;
        temp->next=NULL;
        current->next=temp;        /*当前节点的后驱指向新节点*/
        temp->prev=current;        /*新节点的前驱指向当前节点*/
        current=temp;            /*当前节点为链表尾节点*/

    }

    return head;
}










/*创建循环链表*/
Node* CycleList(Node *head)
{
    if(NULL == head)/*分配头节点空间*/
        head=(Node*)malloc(sizeof(Node)),head->next=NULL;

    Node *current=head , *temp;
    char ch;

    while(1)
    {
        cout<<"\n input elem:";
        cin>>ch;
        if('#' == ch)            /*#结束输入*/
            break;
        temp=(Node *) malloc ( sizeof(Node) );
        temp->elem=ch;
        temp->next=NULL;
        current->next=temp;        /*当前节点的后驱指向新节点*/
        current=temp;            /*当前节点为链表尾节点*/

    }
    current->next=head;            /*尾节点指向头节点*/
    return head;
}







二、链表操作

  包括单链表的增加节点、删除节点、输出链表等







/*插入节点*/

Node *InsertNode(Node *head , char elem)
{
    if( NULL == head || NULL == elem )
        return head;

    Node *current=head->next;    /*当前节点*/
    Node *prev=head;            /*前驱节点*/
    Node *temp;                    /*过渡节点*/
    
    while(current)                /*移动至尾节点*/
    {
        prev=current;
        current=current->next;    
    }

    temp=(Node*) malloc( sizeof(Node) );
    temp->elem=elem;
    temp->next=NULL;
    prev->next=temp;            /*尾节点的后驱指向新节点*/

    return head;

}










/*删除节点*/
Node *DeleteNode(Node *head,char elem)
{
    if(NULL == head || NULL == elem)
        return head;
    if(NULL == head->next)
        return head;

    Node *prev,*current;
    prev=head;
    current=head->next;

    while(current)
    {
        if(current->elem == elem)        /*匹配节点元素*/
        {
            prev->next=current->next;    /*前驱节点的后驱指向当前节点的下一个节点*/
            free(current);                /*释放当前节点*/
            return head;
        }
        prev=current;
        current=current->next;            /*移动至下一个节点*/
    }

    return head;

}










/*
输出链表
*/
void PrintList(Node *head)
{
    Node * current=head->next;
    cout<<"\n List are:";
    while(NULL != current)
    {
        if(NULL != current->elem)
            cout<<setw(5)<<current->elem;
        current=current->next;
    }

    cout<<"\n";
}





三、单链表逆置

  单链表逆置在各公司的笔试题中比较常见,以下是其中一种实现。

  算法描述:将链表中每一个节点插入到头结点之后。

  


  代码如下:





/*单链表逆置*/
Node *ReverseList(Node *head)
{
    if(NULL == head)
        return head;
    if(NULL == head->next)
        return head;
    if(NULL == head->next->next)
        return head;

    Node *curr=head->next;  /*当前节点*/
    head->next=NULL;
    Node *temp;

    while(curr)
    {
        temp=curr->next;    /*暂存下一个节点*/
        /*把当前节点插入到head节点后*/
        curr->next=head->next;
        head->next=curr;

        curr=temp;            /*移动至下一个节点*/
    }

    return head;

}







四、求单链表中间节点

  在笔试题中比较常见,通常题目描述是:给出一个单链表,不知道节点N的值,怎样只遍历一次就可以求出中间节点。

  算法描述:设立两个指针p1,p2,p1每次移动1个节点位置,p2每次移动2个节点位置,当p2移动到尾节点时,p1指向中间节点。

  


  代码如下:







/*求中间节点*/
Node * MiddleNode(Node *head)
{
    if(NULL == head)
        return head;
    if(NULL == head->next)
        return head->next;

    Node *p1,*p2;
    p1=head;
    p2=head;

    while(p2->next)
    {
        /*p2节点移动2个节点位置*/
        p2=p2->next;
        if(p2->next)                    /*判断p2后驱节点是否存在,存在则再移动一次*/
            p2=p2->next;
        /*p1节点移动1个节点位置*/
        p1=p1->next;

    }
    return p1;

}





五、合并有序单链表

  问题描述:合并2个有序单链表,合并后的链表也是排好序的。

  算法描述:对链表A中的每一个节点元素,查找其在链表B中的插入位置,并在B中插入该元素。

  代码如下:





/*合并有序单链表*/
Node * MergeList(Node * h1,Node * h2)
{
    if(NULL == h1 || NULL == h2)
        return h1;
    if(NULL == h1->next )
        return h2;
    if(NULL == h2->next)
        return h1;

    Node * curr1,*curr2,*prev1,*temp;
    prev1=h1;        /*链表1的前驱节点*/
    curr1=h1->next;    /*链表1的当前节点*/
    curr2=h2->next;    /*链表2的当前节点*/
    temp=h2;
    while(curr2)
    {
        while(curr1 && curr1->elem < curr2->elem)/*链表1指针移动至大或等于链表2当前元素的位置*/
            prev1=curr1,curr1=curr1->next;

        /*在链表1中插入链表2的当前元素*/
        temp=curr2->next;/*暂存链表2的下一个节点*/
        prev1->next=curr2;
        curr2->next=curr1;

        /*链表1移动至新节点*/
        curr1=curr2;
        /*链表2移动至下一个节点*/
        curr2=temp;
    }

    return h1;

}






六、判断链表是否有环

  判断链表是否有环即是判断链表是否为循环链表,算法较为简单,一次遍历判断尾指针是否指向头指针即可。
  代码如下:






/*判断链表是否有环(循环链表)*/
bool IsCycleList(Node *head)
{
    if(NULL== head)
        return false;
    if(NULL == head->next)
        return false;
    Node *current=head->next;
    while(current)
    {
        if(head == current->next)
            return true;
        current=current->next;
    }
    return false;
}








七、总结

  以上实现了链表的一些常见操作,源文件LinkList.cpp全部代码如下: 






/*
* 作者: 达闻东
* 修改日期: 2010-04-28 17:10
* 描述: 实现链表的常见操作
*
*/
#include<iostream>
#include<iomanip>
using namespace std;

/*单链表节点结构*/ typedef struct NodeType { char elem; NodeType *next; }Node; /*双链表节点结构*/ typedef struct DNodeType { char elem; DNodeType *next; DNodeType *prev; }DNode;

/*=============================================================================*/
/* 创建链表 */ Node * CreateList(Node *head) { if(NULL == head)//分配头节点空间 head=(Node*)malloc(sizeof(Node)), head->next=NULL; Node *current=head , *temp; char ch; while(1) { cout<<"\n input elem:"; cin>>ch; if('#' == ch) /*#结束输入*/ break; temp=(Node *) malloc ( sizeof(Node) ); temp->elem=ch; temp->next=NULL; current->next=temp; /*当前节点的后驱指向新节点*/ current=temp; /*当前节点为链表尾节点*/ } return head; }
/*=============================================================================*/
/* 输出链表 */ void PrintList(Node *head) { Node * current=head->next; cout<<"\n List are:"; while(NULL != current) { if(NULL != current->elem) cout<<setw(5)<<current->elem; current=current->next; } cout<<"\n"; }

/*=============================================================================*/

/*插入节点*/ Node *InsertNode(Node *head , char elem) { if( NULL == head || NULL == elem ) return head; Node *current=head->next; /*当前节点*/ Node *prev=head; /*前驱节点*/ Node *temp; /*过渡节点*/ while(current) /*移动至尾节点*/ { prev=current; current=current->next; } temp=(Node*) malloc( sizeof(Node) ); temp->elem=elem; temp->next=NULL; prev->next=temp; /*尾节点的后驱指向新节点*/ return head; }

/*=============================================================================*/

/*删除节点*/ Node *DeleteNode(Node *head,char elem) { if(NULL == head || NULL == elem) return head; if(NULL == head->next) return head; Node *prev,*current; prev=head; current=head->next; while(current) { if(current->elem == elem) /*匹配节点元素*/ { prev->next=current->next; /*前驱节点的后驱指向当前节点的下一个节点*/ free(current); /*释放当前节点*/ return head; } prev=current; current=current->next; /*移动至下一个节点*/ } return head; }

/*=============================================================================*/

/*单链表逆置*/ Node *ReverseList(Node *head) { if(NULL == head) return head; if(NULL == head->next) return head; if(NULL == head->next->next) return head; Node *curr=head->next; /*当前节点*/ head->next=NULL; Node *temp; while(curr) { temp=curr->next; /*暂存下一个节点*/ /*把当前节点插入到head节点后*/ curr->next=head->next; head->next=curr; curr=temp; /*移动至下一个节点*/ } return head; }

/*=============================================================================*/

/*求中间节点*/ Node * MiddleNode(Node *head) { if(NULL == head) return head; if(NULL == head->next) return head->next; Node *p1,*p2; p1=head; p2=head; while(p2->next) { /*p2节点移动2个节点位置*/ p2=p2->next; if(p2->next) /*判断p2后驱节点是否存在,存在则再移动一次*/ p2=p2->next; /*p1节点移动1个节点位置*/ p1=p1->next; } return p1; }

/*=============================================================================*/

/*合并有序单链表*/ Node * MergeList(Node * h1,Node * h2) { if(NULL == h1 || NULL == h2) return h1; if(NULL == h1->next ) return h2; if(NULL == h2->next) return h1; Node * curr1,*curr2,*prev1,*temp; prev1=h1; /*链表1的前驱节点*/ curr1=h1->next; /*链表1的当前节点*/ curr2=h2->next; /*链表2的当前节点*/ temp=h2; while(curr2) { while(curr1 && curr1->elem < curr2->elem)/*链表1指针移动至大或等于链表2当前元素的位置*/ prev1=curr1,curr1=curr1->next; /*在链表1中插入链表2的当前元素*/ temp=curr2->next;/*暂存链表2的下一个节点*/ prev1->next=curr2; curr2->next=curr1; /*链表1移动至新节点*/ curr1=curr2; /*链表2移动至下一个节点*/ curr2=temp; } return h1; }

/*=============================================================================*/

/*创建双链表*/ DNode * DoubleList(DNode *head) { if(NULL == head)//分配头节点空间 head=(DNode*)malloc(sizeof(DNode)) , head->prev=NULL , head->next=NULL; DNode *current=head , *temp; char ch; while(1) { cout<<"\n input elem:"; cin>>ch; if('#' == ch) /*#结束输入*/ break; temp=(DNode *) malloc ( sizeof(DNode) ); temp->elem=ch; temp->next=NULL; current->next=temp; /*当前节点的后驱指向新节点*/ temp->prev=current; /*新节点的前驱指向当前节点*/ current=temp; /*当前节点为链表尾节点*/ } return head; }

/*=============================================================================*/
/*输出双链表*/
void PrintDoubleList(DNode *head)
{
if(NULL == head)
return;

DNode * p;
p=head;
cout<<"\n DoubleList are:";
while(p->next)
{
p=p->next;
if(p->elem)
cout<<setw(5)<<p->elem;

}

cout<<"\n DoubleList are:";
while(p->prev)
{
if(p->elem)
cout<<setw(5)<<p->elem;
p=p->prev;
}

}

/*=============================================================================*/
/*创建循环链表*/ Node* CycleList(Node *head) { if(NULL == head)/*分配头节点空间*/ head=(Node*)malloc(sizeof(Node)),head->next=NULL; Node *current=head , *temp; char ch; while(1) { cout<<"\n input elem:"; cin>>ch; if('#' == ch) /*#结束输入*/ break; temp=(Node *) malloc ( sizeof(Node) ); temp->elem=ch; temp->next=NULL; current->next=temp; /*当前节点的后驱指向新节点*/ current=temp; /*当前节点为链表尾节点*/ } current->next=head; /*尾节点指向头节点*/ return head; }
/*=============================================================================*/

/*判断链表是否有环(循环链表)*/ bool IsCycleList(Node *head) { if(NULL== head) return false; if(NULL == head->next) return false; Node *current=head->next; while(current) { if(head == current->next) return true; current=current->next; } return false; }
int main()
{
Node * head,*p;
Node * head2,*head3;
DNode * dHead;
char ch;
head = NULL;
head2=NULL;
head3=NULL;
dHead=NULL;

//head=(Node*) malloc ( sizeof( Node) );
//head->next = NULL;

//创建单链表
head=CreateList(head);
PrintList(head);

head2=CreateList(head2);
PrintList(head2);

//插入节点

cout<<"\n input elem to insert:";
cin>>ch;
InsertNode(head,ch);
PrintList(head);

//删除节点

cout<<"\n input elem to delete:";
cin>>ch;
DeleteNode(head,ch);
PrintList(head);

//单链表逆置

head=ReverseList(head);
cout<<"\n Reversed !";
PrintList(head);

//求中间节点

p=MiddleNode(head);
cout<<"\n Middle Node is:";
cout<<p->elem<<endl;

//合并有序单链表

MergeList(head,head2);
cout<<"\n Merged!";
PrintList(head);

//创建双链表

dHead=DoubleList(dHead);
PrintDoubleList(dHead);

/*创建循环链表并判断是否有环*/
head3=CycleList(head3);
cout<<IsCycleList(head3);
return 0;
}




原文链接:http://www.cnblogs.com/xnwyd/archive/2010/04/28/1723151.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: