引入跳跃链表的目的是为了加速查找过程。而加速策略其中一个非常重要的观点就是并非所有的元素使用的频率都相同。我们自然希望高频使用的元素在链表的头部,而低频的在链表尾部。单向链表和双向链表需要进行顺序查找以定位某个元素,还可以用某种方法动态地组织链表,从而提高查找效率。有许多不同的方法可以组织链表,比较常见的有如下四种:
- 前移法:在找到需要的元素之后,把它放到链表的开头。
- 换位法:在找到需要的元素之后,只要它不在链表的开头就与其前驱节点交换位置。
- 计数法:根据元素被访问的次数,对链表进行排序。
- 排序法:根据被考察信息自身的属性,对链表进行排序。
前移法代码实现如下:
// 自组织链表(前移法)实现
#include<iostream>
using namespace std;
// 节点类
template<class T>
class Node {
public:
Node() {
next = 0;
}
Node(T e, Node* p = 0) :data(e), next(p) {}
T data; //节点信息
Node<T>* next; //下一节点地址
};
// 单向链表类
template<class T>
class ZList {
public:
ZList();
virtual ~ZList();
bool isEmpty() { //是否为空链表
return 0 == head;
}
void addToHead(T); //在头结点添加新节点
void deleteNode(T); //删除指定节点
void visit(T); //访问指定节点
void print();
private:
Node<T>* head; //头节点
};
template<class T>
ZList<T>::ZList() {
head = 0;
}
template<class T>
ZList<T>::~ZList(){
for (Node<T>* p = 0; !isEmpty();) {
p = head->next;
delete head;
head = p;
}
}
template<class T>
void ZList<T>::print() {
Node<T>* p = head;
while (p != NULL) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
template<class T>
void ZList<T>::addToHead(T d) {
head = new Node<T>(d, head);
}
template<class T>
void ZList<T>::deleteNode(T d) {
if (head == 0) { // if non-empty list;
return;
} else if (head->data == d) {
Node<T>* tmp = head;
head = head->next;
delete tmp;
return;
}
Node<T>* p = head;
while (p->next != NULL && p->next->data != d) {
p = p->next;
}
if (p->next != NULL) {
Node<T>* tmp = p->next;
p->next = tmp->next;
delete tmp;
}
}
template<class T>
void ZList<T>::visit(T d) {
if (head == 0) { // if non-empty list;
return;
} else if (head->data == d) {
cout << "visit " << d << endl;
return;
}
Node<T>* p = head;
while (p->next != NULL && p->next->data != d) {
p = p->next;
}
if (p->next != NULL) {
Node<T>* tmp = p->next;
p->next = tmp->next;
Node<T>* tmp_head = head;
head = tmp;
head->next = tmp_head;
}
}
int main() {
ZList<int> list;
list.addToHead(10);
list.addToHead(20);
list.addToHead(30);
list.print();
list.visit(10);
list.print();
return 0;
}