向量、連結串列、棧和佇列的基本實現
阿新 • • 發佈:2018-11-16
目錄
一、一點感想
自學資料結構和演算法到現在時間也不短了,一直猶豫著要不要寫一寫向量等幾個最最基本的資料結構,因為總覺得是最基本的,太容易了,不想花這個時間去寫。然而學著學著慢慢發現,雖然這個很基本,但我並不一定能夠做好(尤其是以前的我)。實際上我幾次因為需要寫過簡單的結構,但是沒有專門寫過,而且體驗也不是很好。最近在學圖演算法,裡面涉及到一些更復雜的演算法和結構,又時需要用上這幾個基本資料結構作為輔助,於是我覺得,不如自己這次認真的寫一下,作為模板放在電腦裡,以後需要用向量什麼的就用自己寫的,這樣可以幫助自己更好的理解資料結構。於是就有了現在的成果。
我覺得事情雖然簡單,但是我還是很有收穫的,因為以前是看上去簡單,但是沒有真正去做這件事,而現在我真正做了,完成了基本的工作,但是有的難點還是沒有克服,比如遍歷問題。這說明之前的認識有很大的錯誤,沒有親力親為就以為自己懂了,那是無知的表現。從某種意義上講,不斷學習的目的之一就是為了克服這種無知,並且做到真正掌握知識和技術。講這些基本的完成了,心裡更有底了,以後在學習更難的內容的時候,我會更加清楚的知道自己以前做過什麼工作,在使用資料結構的時候,也會有更好的掌控。
二、程式碼
1、Vector
#ifndef VECTOR__H__ #define VECTOR__H__ #include <cstdio> template <typename T> class Vector { protected: //受保護的成員外部是不可訪問的 int size, N; T* a; void check_overflow(); void check_underflow(); public: Vector(); Vector(T e); Vector(T* a, int len); ~Vector() { delete [] a; } void print() { print(0, N); } void print(int st, int end); int getSize() { return N; } T operator[](int id) { return a[id]; } void reverse(); void insert(T e); void insert(int id, T e); T del(int id); T del() { return del(N - 1); } }; template <typename T> Vector<T>::Vector() { size = 1; N = 0; a = new T[size]; } template <typename T> Vector<T>::Vector(T e) { size = 2; N = 1; a = new T[size]; a[0] = e; } template <typename T> Vector<T>::Vector(T *arr, int len) { N = len; size = 2 * len; a = new T[size]; for (int i = 0; i < len; i++) a[i] = arr[i]; } template <typename T> void Vector<T>::insert(T e) { check_overflow(); a[N++] = e; } template <typename T> void Vector<T>::insert(int id, T e) { check_overflow(); for (int i = N; i > id; i++) a[i] = a[i - 1]; ++N; a[id] = e; } template <typename T> T Vector<T>::del(int id) { T tmp = a[id]; check_underflow(); for (int i = id; i < N; i++) a[i] = a[i + 1]; --N; return tmp; } template <typename T> void Vector<T>::print(int st, int end) { printf("len : %d\n", end - st); for (int i = st; i < end; i++) printf("%d : %d\n", i, a[i]); } template <typename T> void Vector<T>::check_overflow() { if (N + 1 > size) { size *= 2; T* tmp = new T[size]; for (int i = 0; i < N; i++) tmp[i] = a[i]; a = tmp; } } template <typename T> void Vector<T>::check_underflow() { if (N - 1 < size / 4) { size /= 2; T* tmp = new T[size]; for (int i = 0; i < N; i++) tmp[i] = a[i]; a = tmp; } } template <typename T> void Vector<T>::reverse() { int t = N / 2; for (int i = 0; i < t; i++) { T tmp = a[i]; a[i] = a[N - 1 -i]; a[N - 1 -i] = tmp; } } #endif
2、 List
#ifndef LIST__H__ #define LIST__H__ #include <cstdio> template <typename T> struct node { T data; node<T> * pred; node<T> * succ; }; template <typename T> class List { private: int N; node<T> *head; node<T> *tail; void init(); public: List() { init(); } List(T e) { init(); insertAsLast(e); } List(T * a, int len); node<T>* first() { return head->succ; } bool isEmpty() { return N == 0; } void insertAsLast(T e); void insertAsFirst(T e); void insert(T e) { insertAsLast(e); } T del() { delFirst(); } T delLast(); T delFirst(); }; template <typename T> void List<T>::init() { N = 0; head = new node<T>; tail = new node<T>; head->pred = NULL; head->succ = tail; tail->pred = head; tail->succ = NULL; } template <typename T> List<T>::List(T * a, int len) { init(); for (int i = 0; i < len; i++) insertAsLast(a[i]); } template <typename T> void List<T>::insertAsFirst(T e) { N++; node<T> *nd = new node<T>; nd->data = e; nd->pred = head; nd->succ = head->succ; head->succ->pred = nd; head->succ = nd; } template <typename T> void List<T>::insertAsLast(T e) { N++; node<T> *nd = new node<T>; nd->data = e; nd->pred = tail->pred; nd->succ = tail; tail->pred->succ = nd; tail->pred = nd; } template <typename T> T List<T>::delFirst() { if (N) { N--; T tmp = head->succ->data; head->succ = head->succ->succ; head->succ->pred = head; return tmp; } else printf("Error! Empty! Cannot delete!"); } template <typename T> T List<T>::delLast() { N--; T tmp = tail->pred->data; tail->pred = tail->pred->pred; tail->pred->succ = tail; return tmp; } #endif
3、Stack
自己在寫的時候,由於對c++繼承機制掌握不夠熟練,陷入編譯錯誤很久,主要在派生類的構造上。派生類的構造需要用初始化列表的方式給出基類的構造。
#ifndef STACK__H__
#define STACK__H__
#include "Vector.h"
template <typename T> class Stack: public Vector<T>
{
public:
Stack(): Vector<T>() { }
Stack(T e): Vector<T>(e) { }
Stack(T *a, int len): Vector<T>(a, len) { }
void push(T e) { this->insert(this->getSize(), e); }
T pop() { return this->del(); }
T top() { return this->a[this->getSize() - 1]; }
};
#endif
4、Queue
#ifndef QUEUE__H__
#define QUEUE__H__
#include "List.h"
template <typename T> class Queue: public List<T>
{
public:
Queue(): List<T>() { }
Queue(T e): List<T>(e) { }
Queue(T *a, int len): List<T>(a, len) {}
void enqueue(T const& e) { this->insertAsLast(e); }
T dequeue() { this->delFirst(); }
};
#endif
三、不足之處
- 這幾個資料結構實現了基本的功能,但是API不算豐富,也許不能完全滿足需求。由於我現在使用資料結構解決問題的經驗很少,對哪些方法比較常用和重要沒有直觀的和深刻的理解,所以我想以後經驗積累了、懂得了需求之後再來不斷豐富自己的資料結構庫,現在先到這裡。
- 有的需求我是切身體會到了的,比如對連結串列實現遍歷的功能,奈何自己能力不夠,對c++的語法功能瞭解不夠,儘管做了嘗試但是還是沒有成功。這個就需要以後自己越來越厲害、積累了知識之後再進行完善了。
- 諸如連結串列沒有解構函式此類的不周到的地方,模板中到底有多少我也不知道。現在只把這些問題記錄下來,等以後學了更多東西再來完善吧!
模板中的bug和程式碼綴餘之處,都留給未來的自己好了。略略略。