算法与数据结构【C++】:跳跃链表

         普通链表有一个严重的缺陷:查找某对象时需要遍历整个链表,直到找到了该元素或者遍历完了整个链表也没有找到,时间复杂度很高。

         为了解决该问题,可以使用跳跃链表。

跳跃链表的特点:

跳跃链表中的元素按照从小到达或从大到小的规则排列,该顺序在向链表加入元素时维护,所以,只能指定向链表插入某个值,不能指定插入位置
跳跃链表使用了二分查找的思想, 查找某个元素的复杂度是O(logn)

跳跃链表最底层(对应代码中的0层)包含了所有元素
跳跃链表第1层(对应代码中的1层)包含了从0层中随机抽取的一半的元素(理论上)
跳跃链表第2层(对应代码中的2层)包含了从1层中随机抽取的一半的元素(理论上)

以此类推

为什么使用随机数?

因为跳跃表在何处插入和删除值未知,很难使用预定算法使得这个链表“平衡”(即上层索引较为平均的分隔下层索引)。所以使用随机数决定,要将新加入的结点存入哪些层

算法中的缺陷:

加入元素时采用随机值决定要插入多少层;但是删除时,必须一律从最高层开始删除,多次添加和删除之后,较高层的插入是根据随机数,删除是必须删除,所以会发生较高层结点较少的情况,降低查找效率。

另外,算法根据随机数进行层数分配,有一定的不可控因素。

        

#include
#include
#include
#include  
#include  
#include
using namespace std;


//结点类
class Node{
	public:
	int value;		//该结点的值
	Node* next;		//该结点的下一个结点
	Node* down;		//该结点对应的下一层结点
	
	Node(int aValue, Node* aNext=0, Node* aDown=0){
		value = aValue;
		next = aNext;
		down = aDown;
	}
}; 

//顺序表,链表中的元素按升序排列
class SortedList{
	public:
	Node* head;		//表头结点
	Node* tail;		//表尾结点
	int length;		//链表长度
	
	SortedList(){
		head = tail = 0;
		length = 0;
	}
	
	
	//插入结点
	//参数:要插入新节点的值;要插入的结点的前一个结点的引用
	Node* insertNode(int value, Node* aheadOfInsert){

		//被插入的结点
		Node* InsertedNode = 0;

		//如果链表为空,调用向头部插入方法
		if (aheadOfInsert==0){
			InsertedNode = insertToHead(value);
		}
		//要在链表尾部插入,直接更新tail
		else if (aheadOfInsert == tail){
			InsertedNode = tail = aheadOfInsert->next = new Node(value, 0);
		}
		//在链表中间插入
		else {
			InsertedNode = aheadOfInsert->next = new Node(value, aheadOfInsert->next);
		}
		length++;
				
		return InsertedNode;
	}


	//删除结点
	//参数:要删除的结点的前一个结点的引用
	//如果要删除第一个结点,则该参数为空
	int deleteNode(Node* aheadOfRemove){
		//链表为空,直接返回-1
		if (head == 0){
			return -1;
		}


		Node* removedNode = 0;
		//链表只有一个结点,删除该结点
		if (head == tail){
			removedNode = head;
			head = tail = 0;
		}

		//参数为空,代表要删除第一个结点。同时更新head
		else if (aheadOfRemove == 0){
			removedNode = head;
			head = head->next;
		}
		//正常删除结点
		else{
			removedNode = aheadOfRemove->next;
			aheadOfRemove->next = aheadOfRemove->next->next;
		}
		length--;
		delete aheadOfRemove;
		
	}

	//判断链表是否为空
	int isEmpty(){
		return head == 0;
	}
	//打印链表内容及相关参数
	void printSelf(){
		printf("SortedList: [");
		for (Node* now=head; now!=0; now=now->next)
		if (now->down == 0)
			printf("%d, ", now->value);
		else
		 	printf("%d( %d), ", now->value, now->down->value);
		printf("]\t\t%d\n", length);
		
	}
	private:
	Node* insertToHead(int value){
		if (head == 0){
			head = tail = new Node(value, NULL, NULL);
			//cout<<"Heading into Empty List"<=0;i--){
			//cout<<"Insert into layer "<value<insertNode(value, aheadOfInsert[i]);
			//cout<<"asdasdasdasdasdas"<=1; i--){
			InsertedNode[i]->down = InsertedNode[i-1];
		}
		length++;
		//打印各个层
		cout<<"================================"<printSelf();
		layers[1]->printSelf();
		layers[2]->printSelf();
		layers[3]->printSelf();
		layers[4]->printSelf();
		cout<<"================================"<=0 && (layers[i]->head==0 || layers[i]->head->value>value); i--){
			aheadOfInsert[i] = 0;
		}
		//如果所有层都为空,直接返回
		if (i==-1)
			return 0;
		currentNode = layers[i]->head;
		
		//从上层到下层遍历,寻找该路径
		for (; i>=0; i--){
			Node* now;
		
			//该循环从一层的链表前方向后方遍历,循环停止的条件有两个:
			//当遇到链表尾:说明该值只可能在下一层找到
			//当遇到比当前值还小的结点,说明要找的值,在当前结点和下一和结点之间,转向下一层寻找
			for (now=currentNode; now->next!=0 && now->next->valuenext);
			aheadOfInsert[i] = now;
			currentNode = now->down;
		}
		
	}
	
	//因为先要从上向下查找到要删除哪个结点,并且需要将查找的路径记录下来
	//这样才能在每一层都删除该结点
	//这个函用于查找该路径,该路径用要删除的结点位置的前一个结点表示,存入aheadOfRemove数组
	//然而,在删除结点时,有如下三种情况:
		//1、该结点不存在这一层,不需要删除,指针为NULL
		//2、该结点是该层的第一个结点,该结点的前一个结点为NULL,指针也为NULL
		//3、找到了该结点,指针正常
	//所以,需要另一个数组表示该结点是否应该被删除,这里使用数组deleteOrNot
	int getRemoveIndex(int value, Node** aheadOfRemove, bool* deleteOrNot){
		int i;
		Node* currentNode = 0;

		//从上层向下层遍历,如果该层为空,或该层第一个值已经大于要删除的值,说明这一层不需要删除结点
		for (i=layerNum; i>=0 && (layers[i]->head==0 || layers[i]->head->value>value); i--){
			aheadOfRemove[i] = 0;
			deleteOrNot[i] = false;
		}
		//循环退出之后,i指向需要有结点有可能被删除的第一个层
		cout<head->value == value){
			i=0;
			while(layers[i]->head!=0 && layers[i]->head->value == value){
				deleteOrNot[i] = true;
				aheadOfRemove[i] = 0;
				i++;
			}
			return 0;
		}
		currentNode = layers[i]->head;
		
		//否则向下沿路径查找,寻找应该删除的结点
		for (; i>=0; i--){
			Node* now;
		
			for (now=currentNode; now->next!=0 && now->next->valuenext);
			if (now->next!=0 && now->next->value == value){
				deleteOrNot[i] = true;
			}
			aheadOfRemove[i] = now;
			currentNode = now->down;
		}
	}

	//删除某个元素的函数
	int remove(int value){
		//每一层需要被删除的结点的前一个结点
		Node* aheadOfRemove[100] = {0};
		//该层的这个结点是否有效,或者说,如果aheadOfRemove【i】==null,是代表不需要删除任何结点,还是删除第一个结点
		bool removeOrNot[100] = {false};
		cout<<"Got removeIndex";
		
		//获取每一层需要被删除的结点的前一个结点
		getRemoveIndex(value, aheadOfRemove, removeOrNot);
		cout<<"Got removeIndex";
		//删除结点
		for (int i=layerNum; i>=0; i--)
			if (removeOrNot[i] == true){
				layers[i]->deleteNode(aheadOfRemove[i]);
			}
		length--;

		//打印结果
		cout<<"================================"<printSelf();
		layers[1]->printSelf();
		layers[2]->printSelf();
		layers[3]->printSelf();
		layers[4]->printSelf();
		cout<<"================================"<=0 && (layers[i]->head==0 || layers[i]->head->value>value); i--);
		if (i==-1)
			return 0;
		cout<<"i = "<head;
		
		Node* now;
		//从上层向下层遍历查找
		for (; i>=0; i--){
			for (now=currentNode; now->next!=0 && now->next->value<=value; now=now->next);
			currentNode = now->down;
		}
		return now;
	}
	
	//随机获取某个结点应该被插入到0-k层
	int getLayerNumRandomly(int supposeLength){
		int k = 0;
		
		//随机数
		int a = rand()%2;
		while(a==0){
			cout< maxLayer)
			k = maxLayer;
			
		return k;
	}
	
	int getMaxLayer(int supposeLength){
		return ceil(log(supposeLength)/log(2));
	}
};

//测试函数

int main(){
	
	SkipList* list = new SkipList();
	list->insert(33);
	list->insert(1);
	list->insert(11);
	list->insert(21);
	list->insert(-1);
	list->insert(45);
	list->insert(37);
	
	Node* result = list->search(11);
	cout<<"Search result: "<value<next->value<remove(11);
	list->remove(-1);
	list->remove(45);
	/*
	for (int i=0; i<=100; i++){
		printf("%d: %d\n", i, list->getMaxLayer(i));
	}
	*/
}











        

        

你可能感兴趣的:(算法与数据结构c++&Java,WilliamCode算法大师,Data,structure)