1. 程式人生 > >c++ 建立有序單鏈表,以及兩個有序單鏈表合併

c++ 建立有序單鏈表,以及兩個有序單鏈表合併

首先是Node結點的建立

//建立結點 
class Node
{ 
    public:
    Node(){
        next=NULL;data=0;
    }
    Node(int n){
        next=NULL;data=n;
    }
    int data;
    Node *next;
};

這道題需要三個函式實現相應功能

列印

void show(Node* first)
{
    Node *p;
    p=first->next;
    while(p!=NULL)
    {
        cout<<
p->data<<" "; p=p->next; } cout<<endl; }

建立有序表

void build(Node *front,int size)
{
    Node *curr,*pre,*p;
    cout<<"please input the data: "<<endl;
    for(int i=0;i<size;i++)
    {
        int data;
        curr=front->next;
        //輸入要插入的數字 
cin>>data; //建立新結點 p=new Node(data); //pre永遠在curr的前面,curr是每次遍歷的開始 pre=front; //當前的結點,數字不大於插入目標時,將目標插在這個結點的前面 while(curr!=NULL&&curr->data<=data) { pre=curr; curr=curr->next; } p->
next=curr; pre->next=p; } //列印這個建立的有序表 show(front); }

將兩個有序表合併為一個有序單鏈表

void  combine(Node* f1,Node* f2,Node *f3,int n,int m)
{
    //建立作為標記的結點,p指向有序表f1,q指向有序表f2,back指向新表f3 
    Node*p,*q,*back;
    p=f1->next;
    q=f2->next;
    back=f3->next;
    //如果兩個有序表滿足,一空一不空,則直接列印不空的那個 
    if (f1->next == NULL && f2->next != NULL)
    {
        cout<<"after combine:"<<endl;
        show(f2);
    }       
    else if(f2->next == NULL && f1->next != NULL)
    {
        cout<<"after combine:"<<endl;
        show(f1);   
    }
    //如果兩有序表都空,輸出blank      
    else if(f1->next==NULL && f2->next==NULL) cout<<"blank"<<endl;
    //兩有序表均非空 
    else 
    {
        //比較兩個有序表中的數字,先插小的,指標前進,繼續比較取小的 
        int t=0;
        while(t<m+n)
        {
            while(p!=NULL && (q==NULL || p->data<=q->data))
            {
            Node *k=new Node(p->data);
            //問題:原來的寫法因為k是建立的孤立結點,沒有連上就用back指去
            //會造成back也脫離f3 
            //back=k;
            //back=k->next;
            //修改成如下,當f3空時,k就是第一個結點了,此後f3非空,將k插入到表尾 
            if(f3->next!=NULL)
                back->next=k;
            else
                f3->next=k;
            back=k;
            p=p->next;
            t++;
            }
            while(q!=NULL && (p==NULL || p->data>=q->data))
            {
            Node *k=new Node(q->data);
            //原理同上一條註釋 
            //back=k;
            //back=k->next;
            if(f2->next!=NULL) 
                back->next=k;
            else
                f2->next=k;
            back=k;
            q=q->next;
            t++;
            }
        }
        cout<<endl<<"after combine:"<<endl;
        //打印合並得到的有序表f3 
        show(f3);       
    }
}

其實思路很容易有,編兩個數字連結串列畫畫就能想明白,兩個有序表,頭節點為 f1和f2,用 p 標記 f1->next ,用 q 標記 f2->next ,建立一個節點 f3,它就是新連結串列的頭節點,用 back 指向它,注意這裡的 f1,f2,f3 ,都是其指向的next的指向為空,而不是它們為空,它們是有指向的。
然後就是比較大小的問題,當兩個有序表,一空一不空,則直接列印不空的那個,重點是都非空的兩個。
最外面一個while循壞,當插入次數不大於兩個表的元素數量,裡面兩個while迴圈

while(p!=NULL && (q==NULL || p->data<=q->data))
while(q!=NULL && (p==NULL || p->data>=q->data))

三個點:
1. p!=NULL 和 q!=NULL,如果沒有這兩個條件就會兩個while跳來跳去
2. q==NULL 在 || 的前面一個,因為執行順序,當為NULL時直接跳出這個while,如果是p->data<=q->data在 || 的前面,那q為NULL時就會報錯,所以先判斷
3. 兩個符號 <=、>=而不是<、>,有了這個等號避免不必要的在兩個while裡跳來跳去,相等時執行當前while裡的語句

ps:可能路過的大佬會有更簡單快速的方法,敬請賜教~