PAT甲級 鏈表題_C++題解

鏈表處理

PAT (Advanced Level) Practice 鏈表題node

目錄

  • 《算法筆記》 重點摘要:靜態鏈表
  • 1032 Sharing (25)
  • 1052 Linked List Sorting (25)
  • 1097 Deduplication on a Linked List (25)
  • 1133 Splitting A Linked List (25)
  • 附: 動態鏈表

《算法筆記》 7.3 鏈表 重點摘要

靜態鏈表 ⭐

(1) 定義

結構體類型名和結構體變量名儘可能不一樣ios

struct Node{
    int address; // 記錄地址(若後面排序則不能以數組下標代替)
    typename data;
    int next;
    XXX...
} node[100001];
(2) 初始化
  • 遍歷全部結點,將性質變量標記爲比正常狀況(如在所給鏈表上)下更小的數字
for (int i = 0; i < 100001; i++){
    node[i].XXX = 0;
}
  • 輸入節點時直接將性質變量的初始值壓入
int n, head, address, key, next;
scanf("%d%d", &n, &head);
for (int i = 0; i < n; i++){
    scanf("%d%d%d", &address, &key, &next);
    node[address] = {address, key, next, 0};
}
(3) 標記

依據題目所給鏈表首地址和各結點信息遍歷鏈表上的結點,標記性質,記錄個數算法

int p = head, count = 0;
while (p != -1){
    XXX = 1;
    count++;
    p = node[p]->next;
}
int count = 0;
for (int p = head; p != -1; p = node[p].next){
    node[p].XXX = 1;
    count++;
}
(4) 排序
bool cmp (Node a, Node b){
    if (a.XXX == -1 || b.XXX = -1){
        // 比較標記性質,如有無效點此性質較小 -> 被放到數組後面
        return a.XXX > b.XXX;
    }
    else{
        // 按要求排序
    }
}

1032 Sharing (25)

題目思路

  • 鏈表結點中添加性質變量 inFirst 記錄是否在第一個鏈表中
  • 初始化時將 inFirst 均置爲 false
  • 結點輸入完畢後,遍歷第一條鏈表,令結點 inFirst = true
  • 遍歷第二條鏈表,檢查結點 inFirst,若爲 true,break跳出循環
  • 檢查第二條鏈表循環變量
    • 若未到鏈表尾,說明找到了和第一條鏈表共享的結點,按 %05d 輸出地址
    • 若爲 -1 說明到鏈表尾未找到,輸出 -1
#include<iostream>
using namespace std;
struct Node{
    char data;
    int next;
    bool inFirst;
} node[100001];
int main()
{
    int head1, head2, n, address, next, p;
    char data;
    scanf("%d%d%d", &head1, &head2, &n);
    for (int i = 0; i < n; i++){
        scanf("%d %c %d", &address, &data, &next);
        node[address] = {data, next, false};
    }
    for (p = head1; p != -1; p = node[p].next)
        node[p].inFirst = true;
    for (p = head2; p != -1; p = node[p].next)
        if (node[p].inFirst == true) break;
    if (p == -1) printf("-1");
    else printf("%05d", p);
    return 0;
}

1052 Linked List Sorting (25)

題目思路

  • 結點中添加性質變量 inList,用 int 型的 0/1 來表示,便於排序中比較
  • 結點中要保留此結點的地址,由於按 key 排序後數組下標將再也不能表示地址
  • 輸入完成後,從頭結點遍歷鏈表,令 inList = 1 並 記錄鏈表中的結點數
  • 排序函數將不在鏈表中的放到後面,在鏈表中的按 key 值排序,故排序後數組的前 count 個即爲新鏈表
  • 輸出時注意數組前一個結點的新 next 應當爲數組下一個結點的地址,而非原鏈表的 next
#include<iostream>
#include<algorithm>
using namespace std;
struct Node{
    int address, key, next, inList;
} node[100001];
bool cmp (Node a, Node b){ return !a.inList || !b.inList ? a.inList > b.inList : a.key < b.key; }
int main()
{
    int n, head, address, key, next, count = 0;
    scanf("%d%d", &n, &head);
    for (int i = 0; i < n; i++){
        scanf("%d%d%d", &address, &key, &next);
        node[address] = {address, key, next, 0};
    }
    for (int i = head; i != -1; i = node[i].next){
        node[i].inList = 1;
        count++;
    }
    if (!count) printf("0 -1\n");
    else{
        sort(node, node+100001, cmp);
        printf("%d %05d\n", count, node[0].address);
        for (int i = 0; i < count - 1; i++) printf("%05d %d %05d\n", node[i].address, node[i].key, node[i+1].address);
        printf("%05d %d %d\n", node[count-1].address, node[count-1].key, -1);
    }
    return 0;
}

1097 Deduplication on a Linked List (25)

題目思路

  • 讀入靜態鏈表結點數據,用一個 set 記錄出現過的數字的絕對值
  • 掃描題目給出的鏈表結點
    • 若其數據域絕對值已經出現過,則放到 removed 容器中
    • 若未出現過,將數據域絕對值加入到集合中,結點放到 result 容器中
  • 先輸出 result 容器,再輸出 removed 容器
  • 注意!!! 容器的大小size()返回值爲一個無符號數,無符號數運算後再比較十分危險
    • for (int i = 0; i < vector.size() - 1; i++ 改成 for (int i = 1; i < vector.size(); i++ 避開 size()-1
#include<iostream>
#include<cmath>
#include<set>
#include<vector>
using namespace std;
struct Node{
    int address, data, next;
} node[100001];
int main()
{
    int head, n, address, data, next;
    scanf("%d%d", &head, &n);
    for (int i = 0; i < n; i++){
        scanf("%d%d%d", &address, &data, &next);
        node[address] = {address, data, next};
    }
    vector<Node> result, removed;
    set<int> occured;
    for (int p = head; p != -1; p = node[p].next){
        if (occured.find(abs(node[p].data)) != occured.end()) removed.push_back(node[p]);
        else{
            occured.insert(abs(node[p].data));
            result.push_back(node[p]);
        }
    }
    for (int i = 1; i < result.size(); i++)
        printf("%05d %d %05d\n", result[i-1].address, result[i-1].data, result[i].address);
    if (result.size() > 0) printf("%05d %d -1\n", result[result.size()-1].address, result[result.size()-1].data);
    for (int i = 1; i < removed.size(); i++)
        printf("%05d %d %05d\n", removed[i-1].address, removed[i-1].data, removed[i].address);
    if (removed.size() > 0) printf("%05d %d -1\n", removed[removed.size()-1].address, removed[removed.size()-1].data);
    return 0;
}

1133 Splitting A Linked List (25)

題目思路

  • 設置全局變量 K,在程序中接收輸入,以便於 cmp 函數使用
  • 在結點中設置 oriorder 變量,記錄其在原始鏈表中的順序,以便於 cmp 函數使用
  • cmp 函數首先將不在鏈表中的放到數組後面,再看若是兩個結點數值分別在 0 或 K 兩側,則按數值域排序,不然仍按原鏈表順序
#include<iostream>
#include<algorithm>
using namespace std;
int K = 0;
struct Node{
    int address, data, next, inList, oriorder;
} node[100001];
bool cmp (Node a, Node b){
    if (!a.inList || !b.inList) return a.inList > b.inList;
    if ((a.data >= 0 && b.data < 0) || (a.data < 0 && b.data >= 0)) return a.data < b.data;
    if ((a.data > K && b.data <= K) || (a.data <= K && b.data > K)) return a.data < b.data;
    return a.oriorder < b.oriorder;
}
int main()
{
    int n, head, address, data, next, count = 0, order = 0;
    scanf("%d%d%d", &head, &n, &K);
    for (int i = 0; i < n; i++){
        scanf("%d%d%d", &address, &data, &next);
        node[address] = {address, data, next, 0, 0}; 
    }
    for (int p = head; p != -1; p = node[p].next){
        node[p].inList = 1;
        node[p].oriorder = order;
        count++;
        order++;
    }
    sort(node, node+100001, cmp);
    for (int i = 0; i < count - 1; i++)
        printf("%05d %d %05d\n", node[i].address, node[i].data, node[i+1].address);
    printf("%05d %d %d\n", node[count-1].address, node[count-1].data, -1);
    return 0;
}

二刷(參考柳婼小姐姐的代碼

  • 遍歷鏈表,前後選取 (-無窮,0), [0,k], (k,+無窮)壓入 result 容器
  • 輸出 result 中的結點即爲所要求的順序
#include<iostream>
#include<vector>
using namespace std;
struct Node{
    int address, data, next;
} node[100000];
int main()
{
    int head, n, k, address, data, next;
    scanf("%d%d%d", &head, &n, &k);
    for (int i = 0; i < n; i++){
        scanf("%d%d%d", &address, &data, &next);
        node[address] = {address, data, next};
    }
    vector<Node> result;
    for (int p = head; p != -1; p = node[p].next)
        if (node[p].data < 0) result.push_back(node[p]);
    for (int p = head; p != -1; p = node[p].next)
        if (node[p].data >= 0 && node[p].data <= k) result.push_back(node[p]);
    for (int p = head; p != -1; p = node[p].next)
        if (node[p].data > k) result.push_back(node[p]);
    for (int i = 1; i < result.size(); i++)
        printf("%05d %d %05d\n", result[i-1].address, result[i-1].data, result[i].address);
    printf("%05d %d -1\n", result[result.size()-1].address, result[result.size()-1].data);
    return 0;
}

附:

動態鏈表

  • 頭結點:數據域不存聽任何內容,指針域指向第一個數據域有內容的結點
  • 最後一個節點的指針域指向 NULL,表示鏈表結尾
(1) 建立鏈表
node *p, *pre, *head;
head  = new node();
head->next = NULL;
pre = head;
for (int i = 0; i < n; i++){
    p = new node;
    p->data = data[i];
    p->next = NULL;
    pre->next = p;
    pre = p;
}
(2) 查找元素
// 查找鏈表中 x 並記錄個數
node *p = head->next;
while (p != NULL){
    if (p->data == x){
        count++;
    }
    p = p->next;
}
(3) 插入元素
// 將 x 插入鏈表第 pos 個位置
node *p = head;
for (int i = 0; i < pos-1; i++){
    p = p->next;
}
node *q = new node;
q->data = x;
q->next = p->next;
p->next = q;
(4) 刪除元素
// 刪除鏈表中數據域爲 x 的結點
node *p = head->next;
node *pre = head;
while (p != NULL){
    if (p->data = x){
        pre->next = p->next;
        delete(p);
        p = pre->next;
    }
    else{
        pre = p;
        p = p->next;
    }
}
相關文章
相關標籤/搜索