add List.h ListNode.h test_list.cpp, sorting algorithms still remain to be added.
This commit is contained in:
221
thu_dsa/chp3/List.h
Normal file
221
thu_dsa/chp3/List.h
Normal file
@@ -0,0 +1,221 @@
|
||||
#ifndef LIST_H_
|
||||
#define LIST_H_
|
||||
|
||||
#include "ListNode.h"
|
||||
|
||||
template <typename T>
|
||||
class List{
|
||||
private:
|
||||
ListNodePosi(T) head;
|
||||
ListNodePosi(T) tail;
|
||||
int size;
|
||||
|
||||
protected:// internal methods
|
||||
|
||||
|
||||
public:
|
||||
//constructors
|
||||
List(); // empty List
|
||||
List(List const &L); // copy from another List
|
||||
List(List const &L, int rank, int n); // copy n elements from L[rank]
|
||||
List(ListNodePosi(T) p, int n); // copy n elements from position p
|
||||
|
||||
//deconstructor
|
||||
~List();
|
||||
|
||||
//read-only interfaces
|
||||
ListNodePosi(T) first() const { return head->succ; }
|
||||
ListNodePosi(T) last() const { return tail->prev; }
|
||||
ListNodePosi(T) find(T const &val) const { return find(val, size, tail); } //find val from all elements of the list
|
||||
ListNodePosi(T) find(T const &val, int n, ListNodePosi(T) p) const; //find val from a range of n elements before p
|
||||
T& operator[](int rank);
|
||||
int getSize() const { return size; }
|
||||
bool empty() const { return size == 0; }
|
||||
|
||||
//writable interfaces
|
||||
|
||||
//insert and delete operations
|
||||
ListNodePosi(T) push_back(T const &val);
|
||||
ListNodePosi(T) push_front(T const & val);
|
||||
ListNodePosi(T) insert_before(int rank, T const &val);
|
||||
ListNodePosi(T) insert_before(ListNodePosi(T) p, T const &val);
|
||||
ListNodePosi(T) pop_back();
|
||||
ListNodePosi(T) pop_front();
|
||||
ListNodePosi(T) pop(int rank);
|
||||
ListNodePosi(T) pop(ListNodePosi(T) p);
|
||||
|
||||
//deduplicate & uniquify
|
||||
int deduplicate();
|
||||
int uniquify();
|
||||
};
|
||||
|
||||
/*----------implementations of class List----------*/
|
||||
|
||||
//constructors
|
||||
template <typename T>
|
||||
List<T>::List(){
|
||||
tail = new ListNode<T>();
|
||||
head = new ListNode<T>();
|
||||
tail->prev = head;
|
||||
head->succ = tail;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
List<T>::List(List const &L) {
|
||||
tail = new ListNode<T>();
|
||||
head = new ListNode<T>();
|
||||
tail->prev = head;
|
||||
head->succ = tail;
|
||||
size = 0;
|
||||
|
||||
ListNodePosi(T) p = L.head->succ;
|
||||
for (int ix = 0, size = L.getSize(); ix != size; ++ix, p = p->succ)
|
||||
push_back(p->val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
List<T>::List(List const &L, int rank, int n){
|
||||
ListNodePosi(T) p = L.head->succ;
|
||||
while (rank--) p = p->succ;
|
||||
|
||||
tail = new ListNode<T>();
|
||||
head = new ListNode<T>();
|
||||
tail->prev = head;
|
||||
head->succ = tail;
|
||||
size = 0;
|
||||
|
||||
for (int ix = 0; ix != n; ++ix, p = p->succ)
|
||||
push_back(p->val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
List<T>::List(ListNodePosi(T) p, int n){
|
||||
tail = new ListNode<T>();
|
||||
head = new ListNode<T>();
|
||||
tail->prev = head;
|
||||
head->succ = tail;
|
||||
size = 0;
|
||||
|
||||
for (int ix = 0; ix != n; ++ix, p = p->succ)
|
||||
push_back(p->val);
|
||||
}
|
||||
|
||||
//deconstructor
|
||||
template <typename T>
|
||||
List<T>::~List(){
|
||||
while (size) pop_back();
|
||||
}
|
||||
|
||||
//read-only interfaces
|
||||
|
||||
template <typename T>
|
||||
ListNodePosi(T) List<T>::find(T const &val, int n, ListNodePosi(T) p) const {
|
||||
while ((p = p->prev) != head && n--)
|
||||
if (p->val == val) return p;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& List<T>::operator[](int rank){
|
||||
ListNodePosi(T) p = head->succ;
|
||||
while (rank--) p = p->succ;
|
||||
return p->val;
|
||||
}
|
||||
|
||||
// writable interfaces
|
||||
|
||||
//insert and delete operations
|
||||
template <typename T>
|
||||
ListNodePosi(T) List<T>::push_back(T const &val){
|
||||
++size;
|
||||
return tail->insertAsPred(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ListNodePosi(T) List<T>::push_front(T const &val) {
|
||||
++size;
|
||||
return head->insertAsSucc(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ListNodePosi(T) List<T>::pop_back() {
|
||||
if (empty()) return nullptr;
|
||||
|
||||
ListNodePosi(T) res = tail->prev;
|
||||
res->prev->succ = tail;
|
||||
tail->prev = res->prev;
|
||||
--size;
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ListNodePosi(T) List<T>::pop_front() {
|
||||
if (empty()) return nullptr;
|
||||
|
||||
ListNodePosi(T) res = head->succ;
|
||||
head->succ = res->succ;
|
||||
res->succ->prev = head;
|
||||
--size;
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ListNodePosi(T) List<T>::insert_before(int rank, T const &val){
|
||||
ListNodePosi(T) p = head->succ;
|
||||
while (rank--) p = p->succ;
|
||||
return insert_before(p, val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ListNodePosi(T) List<T>::insert_before(ListNodePosi(T) p, T const &val){
|
||||
++size;
|
||||
return p->insertAsPred(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ListNodePosi(T) List<T>::pop(int rank){
|
||||
if (rank >= size || rank < 0) return nullptr;
|
||||
|
||||
ListNodePosi(T) p = head->succ;
|
||||
while (rank--) p = p->succ;
|
||||
return pop(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ListNodePosi(T) List<T>::pop(ListNodePosi(T) p){
|
||||
p->prev->succ = p->succ;
|
||||
p->succ->prev = p->prev;
|
||||
--size;
|
||||
return p;
|
||||
}
|
||||
|
||||
//deduplicate & uniquify
|
||||
template <typename T>
|
||||
int List<T>::deduplicate(){
|
||||
int oldSize = size;
|
||||
ListNodePosi(T) p = head->succ;
|
||||
ListNodePosi(T) tmp;
|
||||
for (; p != tail; p = p->succ){
|
||||
for(tmp = head->succ; tmp != p; tmp = tmp->succ){
|
||||
if(tmp->val == p->val){
|
||||
pop(tmp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return oldSize - size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int List<T>::uniquify(){
|
||||
if (empty()) return 0;
|
||||
|
||||
int oldSize = size;
|
||||
ListNodePosi(T) p = head->succ;
|
||||
while ((p = p->succ) != tail)
|
||||
if (p->val == p->prev->val) pop(p);
|
||||
return oldSize - size;
|
||||
}
|
||||
|
||||
#endif
|
||||
55
thu_dsa/chp3/ListNode.h
Normal file
55
thu_dsa/chp3/ListNode.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef LISTNODE_H_
|
||||
#define LISTNODE_H_
|
||||
|
||||
#define ListNodePosi(T) ListNode<T>*
|
||||
|
||||
template <typename T>
|
||||
class ListNode{
|
||||
public:
|
||||
ListNodePosi(T) prev;
|
||||
ListNodePosi(T) succ;
|
||||
T val;
|
||||
|
||||
//constructor
|
||||
ListNode();
|
||||
ListNode(T val, ListNodePosi(T) const &p = nullptr, ListNodePosi(T) const &s = nullptr);
|
||||
|
||||
//external interfaces
|
||||
ListNodePosi(T) insertAsPred(T const &val);
|
||||
ListNodePosi(T) insertAsSucc(T const &val);
|
||||
};
|
||||
|
||||
/*----------implementation of class ListNode----------*/
|
||||
|
||||
//constructor
|
||||
template <typename T>
|
||||
ListNode<T>::ListNode(){
|
||||
prev = nullptr;
|
||||
succ = nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ListNode<T>::ListNode( T v, ListNodePosi(T) const &p = nullptr, ListNodePosi(T) const &s = nullptr ){
|
||||
val = v;
|
||||
prev = p;
|
||||
succ = s;
|
||||
}
|
||||
|
||||
//external interfaces
|
||||
template <typename T>
|
||||
ListNodePosi(T) ListNode<T>::insertAsPred(T const &val){
|
||||
ListNodePosi(T) newNode = new ListNode<T>(val, prev, this);
|
||||
prev->succ = newNode;
|
||||
prev = newNode;
|
||||
return newNode;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ListNodePosi(T) ListNode<T>::insertAsSucc(T const &val){
|
||||
ListNodePosi(T) newNode = new ListNode(val, this, succ);
|
||||
succ->prev = newNode;
|
||||
succ = newNode;
|
||||
return newNode;
|
||||
}
|
||||
|
||||
#endif
|
||||
142
thu_dsa/chp3/test_list.cpp
Normal file
142
thu_dsa/chp3/test_list.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "List.h"
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
void test_constructor1();
|
||||
void test_constructor2();
|
||||
void test_push();
|
||||
void test_pop();
|
||||
void test_find();
|
||||
void test_deduplicate();
|
||||
void test_uniquify();
|
||||
|
||||
int main(){
|
||||
cout << "Running tests......" << endl;
|
||||
test_constructor1();
|
||||
test_constructor2();
|
||||
test_push();
|
||||
test_pop();
|
||||
test_find();
|
||||
test_deduplicate();
|
||||
test_uniquify();
|
||||
|
||||
cout << "All tests passed." << endl;
|
||||
system("pause");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_constructor1(){
|
||||
List<double> l;
|
||||
assert(l.getSize() == 0);
|
||||
assert(l.empty());
|
||||
}
|
||||
|
||||
void test_constructor2(){
|
||||
List<int> l1;
|
||||
int i[] = { 5,6,8,9,7,3,4,1,2,0 };
|
||||
for (int ix = 0; ix != 10; ix++)
|
||||
l1.push_back(i[ix]);
|
||||
|
||||
List<int> l2(l1);
|
||||
for (int ix = 0; ix != 10; ix++)
|
||||
assert(l2[ix] == i[ix]);
|
||||
|
||||
List<int> l4(l1.first(), 5);
|
||||
for (int ix = 0; ix != 5; ix++)
|
||||
assert(l4[ix] == i[ix]);
|
||||
assert(l4.getSize() == 5);
|
||||
|
||||
List<int> l5(l1.last(), 1);
|
||||
assert(l5.getSize() == 1);
|
||||
assert(l5.first()->val == 0);
|
||||
|
||||
List<int> l3(l1, 3, 6);
|
||||
assert(l3.getSize() == 6);
|
||||
for (int ix = 0; ix != 6; ix++)
|
||||
assert(l3[ix] == i[3+ix]);
|
||||
}
|
||||
|
||||
void test_push(){
|
||||
List<double> l;
|
||||
double d[] = { 1.2, 3.4, 5.6, 7.8, 9.0 };
|
||||
for (int ix = 0; ix != 5; ix++)
|
||||
l.push_back(d[ix]);
|
||||
for (int ix = 0; ix != 5; ix++)
|
||||
assert(l[ix] == d[ix]);
|
||||
|
||||
List<int> l1;
|
||||
int i[] = { 5,6,8,9,7,3,4,1,2,0 };
|
||||
for (int ix = 0; ix != 10; ix++)
|
||||
l1.push_front(i[ix]);
|
||||
for (int ix = 0; ix != 10; ix++)
|
||||
assert(l1[ix] == i[9-ix]);
|
||||
|
||||
//test insert_before
|
||||
assert(l1.insert_before(0, 12)->val == 12);
|
||||
assert(l1.getSize() == 11);
|
||||
assert(l1.insert_before(11, 14)->val == 14);
|
||||
assert(l1.getSize() == 12);
|
||||
}
|
||||
|
||||
void test_pop(){
|
||||
List<int> l1;
|
||||
int i[] = { 5,6,8,9,7,3,4,1,2,0 };
|
||||
for (int ix = 0; ix != 10; ix++)
|
||||
l1.push_back(i[ix]);
|
||||
|
||||
assert(l1.pop_back()->val == 0);
|
||||
assert(l1.pop_back()->val == 2);
|
||||
assert(l1.pop_front()->val == 5);
|
||||
assert(l1.pop_front()->val == 6);
|
||||
assert(l1.getSize() == 6);
|
||||
|
||||
assert(l1.pop(3)->val == 3);
|
||||
assert(l1.pop(5) == nullptr);
|
||||
ListNodePosi(int) p = l1.first();
|
||||
assert(l1.pop(p)->val == 8);
|
||||
}
|
||||
|
||||
void test_find(){
|
||||
List<int> l1;
|
||||
int i[] = { 5,6,8,9,7,3,4,1,2,0 };
|
||||
for (int ix = 0; ix != 10; ix++)
|
||||
l1.push_back(i[ix]);
|
||||
|
||||
assert(l1.find(8)->val == 8);
|
||||
assert(l1.find(7)->val == 7);
|
||||
assert(l1.find(12) == nullptr);
|
||||
|
||||
assert(l1.find(7, 5, l1.last())->val == 7);
|
||||
assert(l1.find(7, 4, l1.last()) == nullptr);
|
||||
}
|
||||
|
||||
void test_deduplicate(){
|
||||
List<int> l1;
|
||||
int i[] = { 5,6,8,9,7,3,4,1,2,0};
|
||||
for (int ix = 0; ix != 10; ix++) {
|
||||
l1.push_front(i[ix]);
|
||||
l1.push_back(i[ix]);
|
||||
}
|
||||
|
||||
assert(l1.getSize() == 20);
|
||||
assert(l1.deduplicate() == 10);
|
||||
assert(l1.getSize() == 10);
|
||||
for (int ix = 0; ix != 10; ix++)
|
||||
assert(l1[ix] == i[ix]);
|
||||
}
|
||||
|
||||
void test_uniquify(){
|
||||
List<int> l1;
|
||||
int i[] = {5,8,12,14,15,19,20,22,29,36};
|
||||
for (int ix = 0; ix != 11; ix++) {
|
||||
l1.push_back(i[ix]);
|
||||
l1.push_back(i[ix]);
|
||||
}
|
||||
|
||||
assert(l1.getSize() == 22);
|
||||
assert(l1.uniquify() == 11);
|
||||
for (int ix = 0; ix != 11; ix++)
|
||||
assert(l1[ix] == i[ix]);
|
||||
}
|
||||
Reference in New Issue
Block a user