順序表
template <class T>
class arrList :public List<T> //表示 arrList 類以公有繼承的方式繼承自 List<T> 類
//公有繼承意味著 List<T> 類的公共成員在 arrList 類中仍然是公共成員,受保護成員在 arrList 類中仍然是受保護成員。
{
private:T* aList; //存儲順序表的實例,以后可以直接拿aList[]當數組用int maxSize;int curLen; //順序表的當前長度int position; //當前處理位置
public:arrList(const int size){maxSize = size;aList = new T[maxSize];curlen = position = 0;}~arrList(){delete[] aList;}void clear(){delete[] aList;curLen = position = 0;aList = new T[maxSize];}//查找操作bool arrList<T>::getPos(int& p, const T value){for (int i = 0; i <= curLen; i++){if (aList[i] == value){p = i;return true;}}return false;}//插入操作bool arrList <T> ::insert(const int p, const T value){if (curLen >= maxSize) //檢測當前數組是否越界{ cout << "overflow"; return false;}if (p<0 || p>curLen) //檢測插入位置是否合法{cout << "illegal";return false;}for (int i = curLen; i > p; i--){aList[i] = aList[i = 1];}aList[p] = value;curLen++;return true;}//刪除操作bool arrList<T> ::delete(const int p){if (curLen <= 0) //判斷元素是否為空,空表不能刪除{cout << "no element to delete \n"<<endl;return false;}if (p<0 || p>curLen-1) //注意這里是p>curLen-1不是curLen{cout << "illegal";return false;}for (int i = p; i < curLen-1; i++){aList[i] = aList[i + 1];}curLen--;//這里不需要再對aList[curLen-1]進行清零,因為curLen長度已經減小了//最后一個元素不在操作范圍內return false;}
};
鏈表?
單鏈表
head 是指向單鏈表開始結點的指針,tail 是指向單鏈表尾結點的指針,對鏈表的訪問只能通過頭尾指針進行操作
頭結點:虛擬結點,值被忽略,不被看做表中的實際元素,避免對空表的處理
操作分別有:
- 結點的定義
- 單鏈表的類型定義
- 定義鏈表的構造函數和析構函數
- 鏈表的檢索
- 鏈表的插入操作
- 鏈表的刪除操作?
說明:Link是模板類,代表著結點
lnkList是單鏈表類,里面存儲著管理鏈表的方法以及首尾指針?
template <class T> class Link //代表鏈表中的一個結點
{
public:T data; //保存結點的內容Link<T>* next; //指向后繼結點的指針(指向Link類的指針)//函數重載,一個是有一個參數的,另一個是有兩個參數的Link(const T info, const Link<T>* nextValue = NULL)//既有下一個結點的地址,又有data//這里是默認值為NULL,即當只傳入data時,默認為最后一個結點{data = info;next = nextValue;}Link(const Link<T>* nextValue)//只指向下一個結點的指針,但是并沒有值{next = nextValue;}
};
//單鏈表的類型定義
//在定義模板類時,必須在類名之前加上模板參數聲明template <class T>
template <class T> class lnkList:public List<T>
{
private:Link<T>* head, * tail;Link<T>* setPos(const int p); //返回線性表指向第p個元素的指針值
public:lnkList(int s);~lnkList();bool isEmpty();...bool getPos(int& p, const T value);
};
//帶有頭結點的單鏈表的構造函數和析構函數
template<class T> lnkList<T>::lnkList(int defSize)
//在類外定義函數的時候要把模板類寫完整了,加上<T>
{head = tail = new Link<T>;
}
template <class T> lnkList<T>::~lnkList()
{Link<T>* tmp;while (head != NULL){tmp = head;head = head->next;delete tmp;
//要先將head值給tmp(注意這里是指針的關系),然后再讓head等于下一個指針
//刪除了tmp也就相當于刪除了第一個head
//如果直接delete head就會喪失對下一個結點的訪問權}
}
//鏈表的檢索
template <class T> Link<T>* lnkList<T>::setPos(int i)
{int count = 0;if (i == -1) return head;Link<T>* p = head->next; //創建一個新結點,p指針是一個指向Link類型變量的指針,//在這個Link類型變量中是while (p != NULL && count < i){p = p->next;count++;}return p;
}
//鏈表的插入
template <class T> bool lnkList<T> ::insert(const int i, const T value)
{Link<T>* p,*q;//調用 setPos 函數找到插入位置的前一個節點if ((p = setPos(i - 1)) == NULL){cout << "非法插入點";return false;}q = new Link<T>(value, p->next); //q是新構建的結點p->next = q; //將新的q結點插入至p結點之后,也就是說p是q的上一個結點if (p == tail)tail = q;return true;
}
//鏈表的刪除
template <class T> bool lnkList<T>::delete(const int i)
{Link<T>* p, * q;if ((p = setPos(i - 1)) == NULL || p == tail){cout << "非法刪除點";return false;}q = p->next;//q是真正的待刪結點if (q == tail){tail = p;p->next = NULL;delete q;}else if (q != NULL){p->next = q->next;delete q;}return true;
}
鏈表實驗題
順序表做法
偶遇順序表難題,用指針+結構體做拼盡全力無法戰勝,用數組做十分鐘輕松戰勝(但是sstream學了一陣子)
#include<iostream>
#include<cmath>
#include<sstream>
using namespace std;
int a[10000], b[10000];
int main()
{string line1, line2;getline(cin, line1);getline(cin, line2);stringstream ss1(line1);stringstream ss2(line2);int m, n;//m是系數,n是指數while (ss1 >> m >> n){a[n] = m;}while (ss2 >> m >> n){b[n] = m;}int len = max(sizeof(a) / 4, sizeof(b) / 4);for (int i = 0; i < len; i++){a[i] += b[i];}for (int i = len - 1; i >= 0; i--){if (a[i] == 0) continue;cout << a[i] << " " << i << " ";}return 0;
}
鏈表做法
#include<iostream>
#include<cmath>
#include<sstream>
using namespace std;
class node
{int data;node* next;node(const int info,node* nextnode){data = info;next = nextnode;}node(node* nextnode){next = nextnode;}
};
class list {};
int main()
{}
#include<iostream>
#include<cmath>
#include<sstream>
using namespace std;
struct node //創建新結點
{int m;//系數int n;//指數node* next;node(int a, int b){m = a;n = b;next = nullptr;}
};
node* creat()//創建多項式列表
{node* head = nullptr; //表示指向第一個結點的指針node* tail = nullptr; //表示當前最新結點的指針,等全部錄入完畢就是指向最后一個結點string ss1;getline(cin, ss1);stringstream sss(ss1);int a, b;while (sss >> a >> b){
//每次新建一個結點,給它一個新的指針node* newnode = new node(a, b); //返回內存地址if (!head) head = tail = newnode;else{
//假設原來鏈表為A-->B-->C,此時tail指向C,當執行ail->next = newnode時候將C和新結點D連接在一起,
// 鏈表變成A-->B-->C-->D,然后再把tail更新成最新的D tail->next = newnode; tail = newnode;}}return head; //返回頭指針就是返回整條鏈表
}
node* add(node* f1, node* f2) {node index(0, 0);node* tail = &index;while (f1 && f2) {if (f1->n > f2->n) {
//經典操作,同創建鏈表里頭的tail->next = f1;tail = tail->next;f1 = f1->next;}else if (f1->n < f2->n) {tail->next = f2;tail = tail->next;f2 = f2->next;}else {
//如果相等的話就復雜了int sum = f1->m + f2->m;node* tmp1 = f1;node* tmp2 = f2;
//先都往后移動一個結點f1 = f1->next;f2 = f2->next;if (sum != 0) {tmp1->m = sum;
//經典操作,連接新結點tmp1并更新tailtail->next = tmp1;tail = tail->next;tail->next = nullptr; // 防止遺留指針,相當于切斷了和原來鏈的聯系
//假設 f1 鏈表為 A(系數 3, 指數 2) -> B(系數 1, 指數 1),f2 鏈表為 C(系數 2, 指數 2) -> D(系數 4, 指數 1)。
// 當處理到指數為 2 的節點 A 和 C 時,系數相加結果為 3 + 2 = 5,將 A 的系數更新為 5 并連接到新鏈表尾部。
// 如果不將 tail->next 置為 nullptr,A 原本的 next 指針仍然指向 B,這會導致新鏈表中在 A 后面錯誤地連接了 B,
// 而后續可能會繼續錯誤地處理這些遺留節點。}else {delete tmp1;}
//tmp2總是要刪的delete tmp2;}}
//其實后面 f1?f1:f2 才是一個整體,如果f1存在,那么就接上f1的值tail->next = f1 ? f1 : f2;
//返回首結點的地址return index.next;
};void print(node* f1)
{node* cur = f1;bool first = true;while (cur){if (!first){cout << " ";}cout << cur->m << " " << cur->n;first = false;cur = cur->next;}
}
void free(node* f)
{while (f){node* tmp = f;f = f->next;delete tmp;}
}
int main()
{node* f1 = creat();node* f2 = creat();node* summ = add(f1, f2);print(summ);free(summ); free(f1);free(f2);return 0;
}
鏈表實驗選做題
?照葫蘆畫瓢總算出來一個,但是需要逆序輸出,但是爺爺懶得寫直接存個數組里頭逆序輸出了hhh
#include<iostream>
#include<sstream>
using namespace std;struct node
{int data;node* next;node(int a){data = a;next = nullptr;}
};
node* creat()
{node* head=nullptr;node* tail=nullptr;string s;getline(cin, s);stringstream ss(s);int a;while (ss >> a){node* newnode = new node(a);if (!head) head = tail = newnode;else {tail->next = newnode;tail = newnode;}}return head;
}
node* order(node* f1, node* f2)
{node index(0);node* tail = &index;while (f1 && f2){if (f1->data < f2->data){tail->next = f1;tail = tail->next;f1 = f1->next;}else if (f1->data > f2->data){tail->next = f2;tail = tail->next;f2 = f2->next;}else{f1 = f1->next;f2 = f2->next;tail->next = f1;tail = tail->next;tail->next = f2;tail = tail->next;}}tail->next= f1 ? f1 : f2;return index.next;
}
void print(node* head)
{int count = 0;int a[100000] = { 0 };node* tail = head;while (tail){count++;a[count] = tail->data;tail = tail->next;}for (int i = count; i >= 1; i--) cout << a[i] << " ";
}
void free(node* f)
{while (f){node* cur = f;f = f->next;delete cur;}
}
int main()
{node* f1 = creat();node* f2 = creat();node* result = order(f1, f2);print(result);free(result);return 0;
}
洛谷 單向鏈表
題目描述
實現一個數據結構,維護一張表(最初只有一個元素?1)。需要支持下面的操作,其中?x?和?y?都是?1?到?106?范圍內的正整數,且保證任何時間表中所有數字均不相同,操作數量不多于?105:
1 x y
?:將元素?y?插入到?x?后面;2 x
?:詢問?x?后面的元素是什么。如果?x?是最后一個元素,則輸出?0;3 x
:從表中刪除元素?x?后面的那個元素,不改變其他元素的先后順序。
輸入格式
第一行一個整數?q?表示操作次數。
接下來?q?行,每行表示一次操作,操作具體見題目描述。
輸出格式
對于每個操作 2,輸出一個數字,用換行隔開。
輸入輸出樣例
輸入?
6 1 1 99 1 99 50 1 99 75 2 99 3 75 2 1
輸出
75 99
一開始寫的完美無瑕的代碼結果T了兩個點
#include<iostream>
#include<sstream>
using namespace std;
struct node
{int data;node* next;node(int n){data = n;next = nullptr;}
};
node* setpos(node* head,int x)
{node* cur = head;while (cur->data != x){cur = cur->next;}return cur;
}
node* insert(node* head,int x,int y)
{node* cur = setpos(head, x);node* cur2 = cur->next;node* newnode=new node(y);newnode->next = cur2;cur->next = newnode;return head;
}
node* remove(node* head,int x)
{node* cur = setpos(head, x);node* cur1 = cur->next; cur->next=cur1->next;delete cur1;return head;
}
void print(node* curnode)
{cout <<curnode->data<<endl;
}
void free(node* head)
{while (head){node* tmp = head;head = head->next;delete tmp;}
}
int main()
{int n,k,x,y;cin >> n;node* index = new node(1);node* cur = nullptr;for (int i = 0; i < n; i++){cin >> k;if (k == 1){cin >> x >> y;index = insert(index, x, y);}else if (k == 2){cin >> x;cur= setpos(index, x);cur = cur->next;if (!cur) {cout << 0<< endl; continue;}print(cur);}else if (k == 3){cin >> x;index = remove(index, x);}}free(index);return 0;
}
?那應該是還得優化,但是怎么優化呢,網上優化代碼看不懂思密達,但是我會寫數組呀嘻嘻
#include<iostream>
#include<sstream>
using namespace std;
int a[1000000]; //a[i]中i表示data,a[i]表示下一個結點的地址(就是第幾位)
void insert()
{int x, y;cin >> x >> y;a[y] = a[x];a[x] = y;
}
void remove()
{int x;cin >> x;a[x] = a[a[x]];
}
int main()
{a[1] = 0;int k,n;cin >> n;for (int i = 0; i < n; i++){cin >> k;if (k == 1) insert();if (k == 2){int x;cin >> x;if (!a[x]){cout << 0 << endl;continue;}else cout << a[x]<<endl;}if (k == 3) remove();}return 0;
}
洛谷 臨值查找
題目描述
給定一個長度為?n?的序列?A,A?中的數各不相同。
對于?A?中的每一個數?Ai?,求:
min1≤j<i?∣Ai??Aj?∣
以及令上式取到最小值的?j(記為?Pi?)。若最小值點不唯一,則選擇使?Aj??較小的那個。
輸入格式
第一行輸入整數?n,代表序列長度。
第二行輸入?n?個整數?A1?~An?,代表序列的具體數值,數值之間用空格隔開。
輸出格式
輸出共?n?1?行,每行輸出兩個整數,數值之間用空格隔開。
分別表示當?i?取?2~n?時,對應的?min1≤j<i?∣Ai??Aj?∣?和?Pi??的值。
輸入輸出樣例
輸入
3 1 5 3
輸出?
4 1 2 1
?全WA(笑)后來發現題目理解錯了,人家讓找最小的data,不是最小的id
修改后還是錯
#include<iostream>
#include<sstream>
#include<cmath>
#include<climits> //使用INT_MAX
using namespace std;
struct node
{int data;int id;node* next = NULL;node(int n,int z){data = n;id = z;}
};
void result(node* head, node* cur)
{int min_ans = INT_MAX;int index = -1;int select_val = INT_MAX;while (head != cur){int cur_data = abs(cur->data - head->data);if (cur_data< min_ans||cur_data==min_ans&&head->data<select_val){min_ans = cur_data;select_val = head->data;index = head->id;}head = head->next;}cout << min_ans << " " << index << endl;
}int main()
{int n,k;cin >> n;node* head = NULL;node* tail = NULL;bool flag = true;for (int i = 1; i <= n; i++){cin >> k;node* newnode = new node(k,i);if (!head) { head = tail = newnode; flag = false; }tail->next = newnode;tail = newnode;if(i!=1) result(head, tail);}return 0;
}
這里出現問題的在于
if (!head) { head = tail = newnode; flag = false; }tail->next = newnode;tail = newnode;
這里在首結點吧tail的next賦值newnode,造成循環鏈表,正確寫法應該是:
if (!head) { head = tail = newnode; flag = false; }else {tail->next = newnode;tail = newnode;}
全部改完以后沒問題了,但是還是T了四個點
用set優化,快速排序,這樣就不用一個一個找了
#include<iostream>
#include<sstream>
#include<cmath>
#include<set>
#include <climits> // 添加頭文件以使用INT_MAX
using namespace std;
int main()
{ios::sync_with_stdio(false);cin.tie(0);int n, val;cin >> n;set<pair<int,int>> nums;for (int i = 1; i <= n; i++){cin >> val;int min_diff = INT_MAX;//記錄最小差值int min_val = INT_MAX;//記錄最小的Ajint ans_id = -1;if (i == 1){nums.insert({ val,i });continue;}auto it = nums.lower_bound({val,0});//nums.end() 返回的末尾迭代器不指向任何有效元素if (it != nums.end()){if (abs(val - it->first) < min_diff || abs(val - it->first) == min_diff && it->first < min_val){min_diff = abs(val - it->first);min_val = val;ans_id = it->second;}}if (it != nums.begin()) {it--;if (abs(val - it->first) < min_diff || abs(val - it->first) == min_diff && it->first < min_val){min_diff = abs(val - it->first);min_val = val;ans_id = it->second;}}cout << min_diff << " " << ans_id<<'\n';nums.insert({ val,i });}return 0;
}
?學到了用set的很多知識,比如:
1.set中每一個元素的鍵值都唯一,所以在向set中插入相同的數據的時候,會插不進去
2.所有元素都會根據元素的字典序進行排序,先比較第一個,第一個一樣大就比較第二個,默認從小到大
3.迭代器聲明時用auto it=nums容器中某個元素,表示這個元素的時候就用 it->first 和 it->second 來表示
4.nums.end()返回的末尾迭代器不指向任何有效元素
5.用于解除cin和cout的綁定,加快速度防止TLE
ios::sync_with_stdio(false);
cin.tie(0);
6.set聲明:set<pair<int,int>>?
用STL寫鏈表(藍橋杯書上的)
#include<iostream>
#include<list>
using namespace std;
list<int> list1;//創建一個STLlist實例
int main()
{int n, m, x, y, z;cin >> n >> m;for (int i = 1; i <= n; i++)list1.push_back(i); //在鏈表尾部添加元素while (m --){cin >> x >> y >> z;list1.remove(x);list<int>::iterator it = find(list1.begin(), list1.end(), y);//也可以用auto it定義if (z == 0) list1.insert(++it, x);if (z == 1) list1.insert(it, x);}for (int x : list1){cout << x << " ";}cout << endl;return 0;
}
知識點:
- list1.push_back(x):將x添加至鏈表的尾部
- pop_back():刪除鏈表尾部元素
- pop_front():刪除鏈表頭部元素
- front():讀取頭部元素
- back():讀取尾部元素
- insert(it,x):在it位置插入元素x
- erase(it):在it位置刪除元素,也可以用list1.remove(x)刪除x元素
- 定義迭代器:
list<int>::iterator it = find(list1.begin(), list1.end(), y);//也可以用auto it定義