Campared with vector, linked list has no requirement in terms of the continulity of the physical adress, although all the elements’ arrangement are logicaly linear.
By virtual of pointers, linked list can be implemented as the figure above. Above all we should define the node class:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20typedef int Rank;
template <typename T>
struct node
{
//members
T data;
node *pred;
node *succ;
//constructor
node(){}
node(T& e,node<T> *p=NULL,node<T> *s=NULL)
{
data=e;
pred=p;
succ=s;
}
//interface
node<T>* insertAsPred(T const & e);
node<T>* insertAsSucc(T const & e);
};
Then we have the list template class:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
template <typename T>
class list
{
private:
int _size;
node<T> *header;
node<T> *trailer;
protected:
void init(); //init when list created
int clear(); //clear all nodes
void copyNodes(node<T>*,int); //copy n nodes from position p
void merge(node<T> *p,int n,list<T> & L,node<T>* q,int m); //merge n nodes from p in this list and m nodes from q in list L
void MergeSort(node<T> *p,int n);
void SelectionSort(node<T> *,int);
void InsertSort(node<T>*,int);
public:
//constructor
list(){init();} //default
list(list<T> const &L); //totally copy list L
list(list<T> const& L,Rank r,int n);//copy n nodes from the rth in list L
list(node<T>* p,int n); //copy n nodes from node p
//destructor
~list(); //delete all nodes including sentinel nodes
//read-only interface
Rank size() const {return _size;}
bool empty(){return (_size<=0);} //return true, if list is empty
T& operator [] (Rank r) const; //overload, support call-by-rank (inefficient)
node<T>* first() const {return header->succ;}//position of the first node
node<T>* last() const {return trailer->pred;}//position of the last node
bool valid(node<T>* p) //check if valid
{return p&&(header!=p)&&(trailer!=p);} //sentinel nodes regarded as NULL
bool disordered() const; //check if list sorted
node<T>* find(T const & e) const
{return find(e,_size,trailer);}
node<T>* find(T &e,int n,node<T>* p) const; //search in unsorted list
node<T>* search(T const & e) const
{return search(e,_size,trailer);}
node<T>* search(T const& e,int n,node<T>* p) const; //search in sorted list
node<T>* selectMax(node<T>* p,int n);
node<T>* selectMax(){return selectMax(header->succ,_size);};
//writable interface
node<T>* insertAsFirst(T const& e);
node<T>* insertAsLast(T const& e);
node<T>* insertP (node<T>* p, T const & e); //insert as the predecessor of node p
node<T>* insertS (node<T>* p, T const & e); //insert as the successor of node p
T remove (node<T>* p); //delete node p and return data of p
void merge(list<T> & L)
{merge(first(), _size, L, L.first(), L.size());} //merge all the list
void sort(node<T>* p, int n); //sort one section
void sort(){sort(first(), _size);} //sort the whole list
int deduplicate(); //duplication removal in unsorted list
int uniquify(); //duplication removal in sorted list
void reverse(); //invert
void InsertionSort ( node<T>* p, int n );
void MergeSort(node<T>* & p, int n);
//traverse
void traverse (void (*) (T& )); //function pointer
template <typename VST> //operator
void traverse(VST &); //function object
};
Implement of partial interface
default constructor
1 | template <typename T> |
overload operator []
1 | template <typename T> |
find
1 | template <typename T> |
insert
1 | //node insertion |
1 | //insertion in list |
construction based on copy
1 | template <typename T> |
1 | template <typename T> //copy n terms from position p |
removal
1 | template <typename T> |
destruction
1 | template <typename T> |
deduplication
1 | template <typename T> |
traverse
1 | template <typename T> |
Sorted List
Assume that type T can be campared directly or ralative operators have been overloaded.
deduplication
The same nodes in linked list should be arranged one by one logically corresponding to sorted vector. Using this characteristic we can implement the removal algorithm of repetitive nodes. Position pointer p and q respectively point to each 2 adjacent nodes, if they are the same, delete q, otherwise turn to next 2 adjacent ones. Iterate like this over and over again until all nodes are checked.1
2
3
4
5
6
7
8
9
10
11
12
13
14template <typename T>
int list<T>::uniquify()
{
if(_size<2) return 0;
int oldsize = _size;
node<T>* p = header->succ;
node<T>* q;
while(trailer != (q=p->succ) )
{
if (p->data != q->data) p=q;
else remove(q);
}
return oldsize-size;
} //O(n)
search
1 | template <typename T> |
Though list is sorted, divide and conquer strategy doesn’t work in this case becase of dynamic memmory strategy where the physical adress has no relation with logical order.
Collator
InsertionSort
The algorthm can be easily describe as: cut the whole list into 2 parts, the sorted prefix and unsorted suffix; repeatly transfer the first term of suffix to prefix through iteration.
Utilize the search algorthm, and we can locate the maxmum element no more than e, therefore we just need pick out element e and insert as the successor of the position returned.1
2
3
4
5
6
7
8
9
10template <typename T>
void list<T>::InsertionSort ( node<T>* p, int n )
{
for (int r=0; r<n; r++)
{
insertS ( search(p->data,r,p), p->data);
p=p->succ;
remove(p->pred);
}
}//O(n^2)
SelectionSort
1 | template <typename T> |
MergeSort
1 | template <typename T> |
When dividing subsequence, the mergesort algorthm of vector and list have subtle but essential difference. Vector supports call-by-rank which means it can determine the mid point in