題目來源:團體程序設計天梯賽-練習集
題目地址:L2-002 鏈表去重
題目大意
將鏈表數據域的值相同(包含絕對值相同)的節點去掉,然後將去掉的節點又重新組成一條鏈表,最後輸出去重後的鏈表和被去掉的節點組成的鏈表。樣例表示如下:
題目分析
這道題的題目難度相對較低,只要你熟悉鏈表的遍歷和刪除操作,就可以順利完成這道題。雖然話是那麼說,但是用對了數據結構可以讓解題事半功倍。
- 設 數組用於存儲輸入的鏈表,我們可以用數組下標表示當前節點地址,就可以避免遍歷時尋址的麻煩
- 設 數組用於存儲被去除節點組成的鏈表,這時我們可以直接順序存儲被去除的節點,而且只需要存儲節點的地址和數據域,這樣我們就可以利用順序知道每個下個節點的地址了。
- 事實上,我們可以發現 相當於鏈表,而 相當於順序表。它們的存儲示意圖如下:
瞭解到上面這些,寫代碼已經順利了(默認你會鏈表的遍歷和刪除),最後再說一下寫題目踩到的坑:
- 地址直接用 類型存儲,沒必要用 ,否則無法用上上述存儲結構(別跟我說用 ,我第一發就是這樣超時的)。
- 格式控制符 “%05d” 表示如果輸出的字符少於5位時,在左邊補 (默認是補空格)。
- 刪除操作需要用到前驅節點 的指針 , 在每次遇到不需要刪除的節點時就要更新,如果單純的直接用上一個節點,就可能用到被去除節點的地址。
代碼如下
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n, cnt;
int one, s, pre;
/**
* lb用於存儲原始鏈表
* re用於存儲原始鏈表中的重複節點
*/
pair<int, int> lb[maxn];
pair<int, int> re[maxn];
set<int> vis;
int main()
{
cin >> one >> n;
for (int i = 1; i <= n; i++) {
int address, num, next;
cin >> address >> num >> next;
lb[address] = make_pair(num, next);
}
cnt = 0;
//遍歷鏈表,s表示當前節點的地址
for (s = one; s != -1; s = lb[s].second) {
int num = lb[s].first;
if (!vis.count(abs(num))) {
vis.insert(abs(num));
//pre記錄下一個節點的前驅節點地址
pre = s;
} else {
//鏈表刪除重複節點操作
lb[pre].second = lb[s].second;
//將刪除的節點存到另一條鏈表
re[cnt].first = num;
re[cnt].second = s;
cnt++;
}
}
for (s = one; s != -1; s = lb[s].second) {
printf("%05d %d ", s, lb[s].first);
if (lb[s].second != -1) printf("%05d\n", lb[s].second);
else printf("-1\n");
}
for (int i = 0; i < cnt; i++) {
printf("%05d %d ", re[i].second ,re[i].first);
if (i != cnt - 1) printf("%05d\n", re[i + 1].second);
else printf("-1\n");
}
return 0;
}
如果本文對你有所幫助,別忘了點贊哦~