1. 程式人生 > >線性表之連結串列複習(僅王道單鏈表題目)

線性表之連結串列複習(僅王道單鏈表題目)

考研408複習,如發現任何錯誤,請私聊,不勝感謝

單鏈表程式碼已更新完畢。

如下:

#include <iostream>
#include <algorithm>
#include <string>
#include <cmath>
#include <iomanip>
#include <cstring>

using namespace std;

typedef struct LNode
{
    int data;
    LNode *next;
}Lnode, *Linklist;
///逆序建立連結串列
Linklist CreatepositiveLinklist(Linklist &head, int n)
{
    head = new Lnode;
    head->next = NULL;
    for(int i=0;i<n;++i)
    {
        Linklist p = new Lnode;
        cin>>p->data;
        p->next = head->next;
        head->next = p;
    }
    return head;
}
///正序建立連結串列
Linklist CreateNegativeLinklist(Linklist &head, int n)
{
    Linklist tail;
    head = new Lnode;
    head->next = NULL;
    tail = head;
    for(int i=0;i<n;++i)
    {
        Linklist p = new Lnode;
        cin>>p->data;
        p->next = NULL;
        tail->next = p;
        tail = p;
    }
    return head;
}
///列印連結串列
void print_Linklist(Linklist head)
{
    if(head->next == NULL)
    {
        cout<<"The Linklist is NULL !"<<endl;
        return;
    }
    while(head->next->next)
    {
        cout<<head->next->data<<" ";
        head = head->next;
    }
    cout<<head->next->data<<endl;
}
///按下標查詢結點
Lnode *Find_Lnode_byid(Linklist head, int key)
{
    if(key == 0)
        return head;
    if(key < 1)
        return NULL;
    int num = 1;
    head = head->next;
    while(head && num < key)
    {
        head = head->next;
        num++;
    }
    return head;
}
///在position處插入節點值為key的元素
void Insert_Lnode(Linklist &head, int position, int key)
{
    if(position <= 0)
    {
        cout<<"輸入不合法,插入失敗!"<<endl;
        return;
    }
    Linklist p = Find_Lnode_byid(head, position-1);
    Linklist temp = new Lnode;
    temp->data = key;
    temp->next = p->next;
    p->next = temp;
}
///刪除位置為position的節點
void Delete_Lnode(Linklist &head, int position)
{
    if(position <= 0)
    {
        cout<<"The input is ERROR!, delete failed!"<<endl;
        return;
    }
    Linklist p = Find_Lnode_byid(head, position);
    Linklist q = p->next;
    p->next = q->next;
}
///求連結串列長度
int Linklist_length(Linklist head)
{
    if(head->next == NULL)
        return 0;
    int num = 0;
    while(head->next)
    {
        num++;
        head = head->next;
    }
    return num;
}

///以下為一些綜合應用分析題,具有詳細題目描述
///1.設計一個遞迴演算法,刪除不帶頭節點的單鏈表L中所有值為x的節點。
void The_first_problem(Linklist &head, int key)
{
    if(head == NULL)
        return;
    if(head->data == key)
    {
        Linklist p = head;
        head = head->next;
        free(p);
        The_first_problem(head, key);
    }
    else
        The_first_problem(head->next, key);
}
///這裡做一個理解說明:函式進行遞迴呼叫時,只是將head進行next操作,並沒有改變被刪除節點的前驅結點的next指向,疑似斷鏈操作
///其實不然,這裡head為呼叫該函式的外層head->next,故這裡實現了head->next=head-next->next的造作過程。
///2.在帶頭節點的單鏈表L中,刪除所有值為x的節點,並釋放其空間,假設值為x的節點不唯一。
Linklist The_second_problem(Linklist &head, int x)
{
    Linklist q = head;
    Linklist p = head->next;
    while(p)
    {
        if(p->data == x)
        {
            q->next = p->next;
            free(p);
            p=q->next;
        }
        else
        {
            p=p->next;
            q=q->next;
        }
    }
    return head;
}

///3.設L為帶頭節點的單鏈表,編寫演算法實現從尾到頭反向輸出每個節點的值
void The_third_problem1(Linklist head)///利用輔助空間解決問題
{
    int *temp = new int[Linklist_length(head)];
    Linklist p = head->next;
    for(int i=0;i<Linklist_length(head); ++i, p=p->next)
    {
        temp[i] = p->data;
    }
    for(int i=Linklist_length(head)-1; i>0; --i)
        cout<<temp[i]<<" ";
    cout<<temp[0]<<endl;
}

void The_third_problem2(Linklist head)///使用遞迴思想解決問題
{
    if(head->next)
        The_third_problem2(head->next);
    cout<<head->data<<" ";
}

///4.試編寫在帶頭節點的單鏈表L中刪除一個最小值節點的高效演算法(假設最小值節點是唯一的)
Linklist The_four_problem(Linklist &head)
{
    ///儲存最小值節點的位置及其前驅位置
    Linklist q = head, p=head->next;
    Linklist mixn = p, mixnpre = q;
    while(p)
    {
        if(p->data < mixn->data)
        {
            mixn = p;
            mixnpre = q;
        }
        p = p->next;
        q = q->next;
    }
    mixnpre->next = mixn->next;
    free(mixn);
    return head;
}
///5.試編寫演算法將帶頭結點的單鏈表就地逆置,所謂就地是指輔助空間複雜度為O(1)
Linklist The_five_problem1(Linklist &head)
{
    Linklist p = head->next;
    Linklist q = p->next;
    head->next = NULL;
    while(p)
    {
        p->next = head->next;
        head->next = p;
        p = q;
        if(q)
            q = q->next;
    }
    return head;
}

Linklist The_five_problem2(Linklist &head)
{
    Linklist pre, p=head->next, r=p->next;
    p->next = NULL;
    while(r)
    {
        pre = p;
        p = r;
        r = r->next;
        p->next = pre;
    }
    head->next = p;
    return head;
}
///6.有一個帶頭節點的單鏈表L,設計一個演算法,使其元素遞增有序
///願你閱盡千帆,歸來仍是少年
Linklist The_six_problem(Linklist &head)
{
    ///採用插入排序思想,即構造一個單鏈表,然後遍歷L,每走一個節點,插入一個節點。
    Linklist p = head->next, r = p->next;
    p->next = NULL;
    p = r;
    r = r->next;
    while(p)
    {
        Linklist temp = head->next, tempre = head;
        while(tempre)
        {
            if(temp == NULL)
            {
                tempre->next = p;
                p->next = NULL;
                break;
            }
            if(p->data < temp->data)
            {
                p->next = temp;
                tempre->next = p;
                break;
            }
            temp = temp->next;
            tempre = tempre->next;
        }
        if(r)
        {
            p = r;
            r = r->next;
        }
        else
            break;
    }
    return head;
}
///7.設在一個帶表頭節點的單鏈表L中所有元素節點的資料值無序,試編寫一個函式,刪除表中所有介於給定的兩個值之間的元素
///人生一棋局,無法跳脫,終究是棋子。
Linklist The_seven_problem(Linklist &head, int a, int b)
{
    Linklist p = head->next;
    Linklist q = head;
    while(p)
    {
        if(p->data >= a && p->data <= b)
        {
            q->next = p->next;
            free(p);
            p = q->next;
        }
        else
        {
            p = p->next;
            q = q->next;
        }
    }
    return head;
}

///8.給定兩個單鏈表,編寫演算法找出兩個連結串列的公共節點
///虛無縹緲者,是否虛幻。
Linklist The_eight_problem(Linklist head1, Linklist head2)
{
    ///明確公共節點的定義,即如果兩個連結串列擁有公共節點,那麼在該節點之後的所有節點都是重合的,即他們最後一個節點必然是重合的。
    int len1 = Linklist_length(head1), len2 = Linklist_length(head2);
    Linklist longlist, shortlist;
    int dist = abs(len1-len2);///兩表長之差
    if(len1 > len2)
    {
        longlist = head1->next;
        shortlist = head2->next;
    }
    else
    {
        longlist = head2->next;
        shortlist = head1->next;
    }
    while(dist--)
    {
        longlist = longlist->next;
    }
    while(longlist)
    {
        if(longlist == shortlist)
            return longlist;
        longlist = longlist ->next;
        shortlist = shortlist ->next;
    }
    return NULL;
}
///9.給定一個帶頭節點的單鏈表,按照遞增次序輸出單鏈表中各節點的資料元素,並釋放節點所佔的儲存空間。(不允許使用陣列做輔助空間)
///向來歷史都是由強者書寫
Linklist The_nine_problem(Linklist &head)
{
    ///巢狀雙重迴圈,遍歷一次找到最小值輸出並釋放節點空間
    while(head->next)
    {
        Linklist p = head->next;
        Linklist pre = head;
        Linklist mixn = p, mixnpre = pre;
        while(p)
        {
            if(p->data < mixn->data)
            {
                mixn = p;
                mixnpre = pre;
            }
            else
            {
                p = p->next;
                pre = pre->next;
            }
        }
        cout<<mixn->data<<endl;
        mixnpre->next = mixn->next;
        free(mixn);
    }
    return head;
}

///10.將一個帶頭節點的單鏈表A分解為兩個帶頭結點的單鏈表的A和B,是的A表中元素為原表奇數序號的元素,B表中元素為原表偶數序號的元素,且保持其相對順序不變。
///逆風翻盤,向陽而生
void The_ten_problem(Linklist &head, Linklist &head1, Linklist &head2)
{
    Linklist tail2;
    head2 = new Lnode;
    head2->next = NULL;
    tail2 = head2;
    Linklist tail1;
    head1 = new Lnode;
    head1->next = NULL;
    tail1 = head1;
    Linklist p = head->next;
    int len = Linklist_length(head);
    for(int i=1;i<=len;i++)
    {
        if(i%2)
        {
            tail1->next=p;
            tail1 = p;
        }
        else
        {
            tail2->next = p;
            tail2 = p;
        }
        p = p->next;
    }
    tail1->next = NULL;
    tail2->next = NULL;
}
///11.設C={a1, b1, a2, b2,......an, bn}為線性表,採用帶頭節點的單鏈表存放,設計一個就地演算法,使A={a1, a2, ...an},B={bn, ...b2, b1}
///與上題思路相同,只不過B單鏈表改成尾插法。
///12.在一個遞增有序的線性表中,有數值相同的元素存在,儲存方式為單鏈表,設計演算法去掉數值相同的元素,是表中不存在相同元素。
Linklist The_twelve_problem(Linklist &head)
{
    Linklist p = head->next;
    Linklist q = p->next;
    while(q)
    {
        if(p->data==q->data)
        {
            while(p->data == q->data)
            {
                if(q->next)
                    q = q->next;
                else
                    break;
            }
            if(q->next)
                p->next = q;
            else
                p->next = q->next;
        }
        p=p->next;
        q=q->next;
    }
    return head;
}
///13.假設有兩個按元素值遞增次序排列的線性表,均以單鏈表形式儲存,歸併為一個按照元素值遞減的=次序排列的單鏈表
///並要求利用原來兩個單鏈表節點存放歸併後的單鏈表
Linklist The_thirteen_problem(Linklist &head1, Linklist &head2)
{
    ///從小開始比較,採用逆序建連結串列方法
    Linklist p = head1->next;
    Linklist q = head2->next;
    Linklist r;
    head1->next = NULL;
    while(p && q)
    {
        if(p->data < q->data)
        {
            r = p->next;
            p->next = head1->next;
            head1->next = p;
            p = r;
        }
        else
        {
            r = q->next;
            q->next = head1->next;
            head1->next = q;
            q = r;
        }
    }
    if(p)
    {
        q = p;
    }
    while(q)
    {
        r = q->next;
        q->next = head1->next;
        head1->next = q;
        q = r;
    }
    free(head2);
    return head1;
}
///14.設A和B是兩個單鏈表(帶頭節點), 其中元素遞增有序,設計一個演算法從A和B中公共元素產生單鏈表C,要求不破壞A和B的節點
Linklist The_fourteen_problem(Linklist &head1, Linklist &head2)
{
    Linklist head = new Lnode;
    head->next = NULL;
    Linklist p = head1->next;
    Linklist q = head2->next;
    Linklist r = head;
    while(p && q)
    {
        if(p->data <q->data)
            p=p->next;
        else if(p->data > q->data)
            q = q->next;
        else
        {
            Linklist s;
            s = new Lnode;
            s->data = p->data;
            s->next = NULL;
            r->next = s;
            r = s;
            p=p->next;
            q=q->next;
        }
    }
    return head;
}
///15.已知兩個連結串列A和B分別表示兩個集合,其元素遞增排列。編制函式,求A和B的交集,並存放於A連結串列之中
Linklist The_fifteen_problem(Linklist &head1, Linklist &head2)
{
    ///較為簡單的歸併演算法,給出王道演算法
    Linklist p = head1->next;
    Linklist q = head2->next;
    Linklist c = head1, u;
    while(p && q)
    {
        if(p->data == q->data)
        {
            c ->next = p;
            c=p;
            p=p->next;
            u = q;
            q=q->next;
            free(u);
        }
        else if(p->data < q->data)
        {
            u = p;
            p=p->next;
            free(u);
        }
        else
        {
            u = q;
            q=q->next;
            free(u);
        }
    }
    while(p)
    {
        u = p;
        p=p->next;
        free(u);
    }
    while(q)
    {
        u = q;
        q=q->next;
        free(u);
    }
    c->next=NULL;
    free(head2);
    return head1;
}
///16.兩個連續子序列,判斷b是否為a的連續子序列
bool The_sixteen_problem(Linklist &head1, Linklist &head2)
{
    Linklist p = head1->next;
    Linklist q = head2->next;
    Linklist pre = p;
    while(p && q)
    {
        if(q->data == p->data)
        {
            q = q->next;
            p = p->next;
        }
        else
        {
            pre = pre->next;
            p = pre;
            q = head2->next;
        }
    }
    if(q == NULL)
        return true;
    return false;
}
///21.單鏈表,查詢連結串列中倒數第k個位置上的節點,若查詢成功,輸出資料並返回1,否則只返回0
bool The_twentyone_problem(Linklist head, int k)
{
    ///演算法思想,p,q同時指向第一個元素,p先開始移動,當p移動到第k個元素時,q之後與p同步向後移動
    ///這樣當p移動到最後一個元素時,q移動到倒數第k個元素
    Linklist p = head->next;
    Linklist q = p;
    int num = 1;
    while(p)
    {
        if(num <= k)
        {
            cout<<"xunhuan "<<p->data<<endl;
            p=p->next;
            num++;
            continue;
        }
        cout<<"p: "<<p->data<<endl;
        p = p->next;
        q = q->next;
    }
    if(num <= k)
        return 0;
    cout<<q->data<<endl;
    return 1;
}
///22.單鏈表,找出兩個連結串列共同字尾的起始位置。說明時間複雜度。
///與第8題相仿,不予贅述
///23.單鏈表,刪除絕對值相等的節點,僅保留第一次出現的節點。
Linklist The_twentythree_problem(Linklist &head, int n)
{
    int *temp = new int[n+1];
    Linklist p=head->next, pre = head;
    memset(temp, 0, n+1);
    while(p)
    {
        int data = p->data>0?p->data:-p->data;
        if(temp[data] == 0)
        {
            p=p->next;
            pre = pre->next;
            temp[data] = 1;
        }
        else
        {
            pre->next = p->next;
            free(p);
            p = pre->next;
        }
    }
    return head;
}
int main()
{
    ios::sync_with_stdio(false);
    Linklist head;
    int n;
    cin>>n;
    head = CreateNegativeLinklist(head, n);
    /*
    Linklist head1, head2;
    int n, m;
    cin>>n>>m;
    head1 = CreateNegativeLinklist(head1, n);
    head2 = CreateNegativeLinklist(head2, m);
    print_Linklist(head);
    cout<<Find_Lnode_byid(head, 3)->data<<endl;
    Insert_Lnode(head, 1, 999);
    print_Linklist(head);
    cout<<Linklist_length(head)<<endl;
    //The_first_problem(head, 5);
    //print_Linklist(head);
    //cout<<Linklist_length(head)<<endl;
    The_second_problem(head, 5);
    print_Linklist(head);
    cout<<Linklist_length(head)<<endl;
    The_third_problem1(head);
    The_third_problem2(head->next);
    head = The_four_problem(head);
    print_Linklist(head);
    head = The_five_problem2(head);
    print_Linklist(head);
    head = The_seven_problem(head, 2, 5);
    The_ten_problem(head, head1, head2);
    print_Linklist(head1);
    print_Linklist(head2);
    head = The_twelve_problem(head);
    print_Linklist(head);
    bool flag = The_sixteen_problem(head1, head2);
    cout<<flag<<endl;
    bool flag = The_twentyone_problem(head, 3);
    cout<<flag<<endl;*/
    head = The_twentythree_problem(head, 20);
    print_Linklist(head);
    return 0;
}