c_cpp 如果用有序链表来表示一个含有Ñ个元素的有序集S,则在最坏情况下,搜索小号中一个元素需要O(n)的计算时间。提高有序链表效率的一个技巧是在有序链表的部分结点处增设附加指针以提高其搜

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 如果用有序链表来表示一个含有Ñ个元素的有序集S,则在最坏情况下,搜索小号中一个元素需要O(n)的计算时间。提高有序链表效率的一个技巧是在有序链表的部分结点处增设附加指针以提高其搜相关的知识,希望对你有一定的参考价值。

//随机化算法 跳跃表
#include "stdafx.h"
#include "RandomNumber.h"
#include <cmath>
#include <iostream>
using namespace std;
 
template<class EType,class KType> class SkipList;
template<class EType,class KType>
class SkipNode
{
	friend SkipList<EType,KType>;
	private:
		SkipNode(int size)
		{
			next = new SkipNode<EType,KType>*[size];
		}
		~SkipNode()
		{
			delete []next;
		}
		EType data;//集合中的元素
		SkipNode<EType,EType> **next;//指针数组 next[i]是第i级指针
};
 
template<class EType,class KType>
class SkipList
{
	public:
		SkipList(KType Large,int MaxE = 10000,float p = 0.5);
		~SkipList();
		bool Search(const KType& k,EType& e) const;
		SkipList<EType,KType>& Insert(const EType& e);
		SkipList<EType,KType>& Delete(const KType& k,EType& e);
		void Output();
	private:
		int Level();
		SkipNode<EType,KType> *SaveSearch(const KType& k);
		int MaxLevel;					//跳跃表级别上界
		int Levels;						//当前最大级别
		RandomNumber rnd;				//随机数产生器
		float Prob;						//用于分配节点级别
		KType TailKey;					//元素键值上界
		SkipNode<EType,KType> *head;	//头结点指针
		SkipNode<EType,KType> *NIL;		//尾节点指针
		SkipNode<EType,KType> **last;	//指针数组
};
 
//构造函数
template<class EType,class KType>
SkipList<EType,KType>::SkipList(KType Large,int MaxE,float p)
{
	Prob = p;
	MaxLevel = ceil(log(float(MaxE))/log(1/p))-1;		//初始化跳跃表级别上界
	TailKey = Large;							//元素键值上界
	Levels = 0;									//初始化当前最大级别
 
	//创建头、尾节点和数组 last
	head = new SkipNode<EType,KType>(MaxLevel+1);
	NIL = new SkipNode<EType,KType>(0);
	last = new SkipNode<EType,KType> *[MaxLevel+1];
	NIL->data = Large;
 
	//将跳跃表初始化为空表
	for(int i=0; i<=MaxLevel; i++)
	{
		head->next[i] = NIL;
	}
}
 
//析构函数
template<class EType,class KType>
SkipList<EType,KType>::~SkipList()
{
	SkipNode<EType,KType> *next;
 
	//删除所有节点
	while(head!=NIL)
	{
		next = head->next[0];
		delete head;
		head = next;
	}
 
	delete NIL;
	delete []last;
}
 
class element
{
	friend int main(void);
	public:
		operator long() const 
		{
			return key;
		}
		element& operator = (long y)
		{
			key = y;
			return *this;
		}
	private:
		int data;
		long key;
};
 
//搜索指定元素k
template<class EType,class KType>
bool SkipList<EType,KType>::Search(const KType& k,EType& e) const
{
	if(k>=TailKey)
	{
		return false;
	}
	//位置p恰好位于指定元素k之前
	SkipNode<EType,KType> *p = head;
	for(int i=Levels; i>=0; i--)//逐渐向下搜索
	{
		while(p->next[i]->data<k)//在第i级链中搜索
		{
			p = p->next[i];//每次搜索尽可能滴接近要搜索的元素
		}
	}
	e = p->next[0]->data;
	return (e==k);
}
 
//搜索指定元素k,并将每一级中遇到的上一个节点存放在数组last中
template<class EType,class KType>
SkipNode<EType,KType> *SkipList<EType,KType>::SaveSearch(const KType& k)
{
	//位置p恰好位于指定元素k之前
	SkipNode<EType,KType> *p = head;
	for(int i = Levels; i>=0; i--)
	{
		while(p->next[i]->data<k)
		{
			p = p->next[i];
		}
		last[i] = p;	//上一个第i级结点
	}
	return (p->next[0]);
}
 
//产生不超过MaxLevel 的随机级别
template<class EType,class KType>
int SkipList<EType,KType>::Level()
{
	int lev = 0;
	while(rnd.fRandom()<Prob)
	{
		lev++;
	}
	return (lev<=MaxLevel)?lev:MaxLevel;
}
 
//插入指定元素e
template<class EType,class KType>
SkipList<EType,KType>& SkipList<EType,KType>::Insert(const EType& e)
{
	KType k = e;//取得元素键值
	if(k>=TailKey)
	{
		cout<<"元素键值超界!"<<endl;
		return *this;
	}
	//检查元素是否已存在
	SkipNode<EType,KType> *p = SaveSearch(k);
	if(p->data == e)
	{
		cout<<"元素已存在!"<<endl;
		return *this;
	}
 
	//元素不存在,确定新节点级别
	int lev = Level();
	//调整个级别指针
	if(lev>Levels)
	{
		for(int i=Levels+1; i<=lev; i++)
		{
			last[i] = head;
		}
		Levels = lev;
	}
 
	//产生新节点,并将新节点插入p之后
	SkipNode<EType,KType> *y = new SkipNode<EType,KType>(lev+1);
	y->data = e;
 
	for(int i=0; i<=lev; i++)
	{
		//插入第i级链
		y->next[i] = last[i]->next[i];
		last[i]->next[i] = y;
	}
	return *this;
}
 
//删除键值为k的元素,并将所删除的元素存入e
template<class EType,class KType>
SkipList<EType,KType>& SkipList<EType,KType>::Delete(const KType& k,EType& e)
{
	if(k>=TailKey)
	{
		cout<<"元素键值超界!"<<endl;
	}
	//搜索待删除元素
	SkipNode<EType,KType> *p = SaveSearch(k);
	if(p->data!=k)
	{
		cout<<"未找到待删除元素!"<<endl;
	}
	//从跳跃表中删除节点
	for(int i=0; i<=Levels && last[i]->next[i] == p; i++)
	{
		last[i]->next[i] = p->next[i];
	}
	//更新当前级别
	while(Levels>0 && head->next[Levels] == NIL)
	{
		Levels--;
	}
	e = p->data;
	delete p;
	return *this;
}
 
//输出集合中的元素
template<class EType,class KType>
void SkipList<EType,KType>::Output()
{
	SkipNode<EType,KType> *y = head->next[0];
	for(;y!=NIL; y=y->next[0])
	{
		cout<<y->data<<' ';
	}
	cout<<endl;
}
 
int main()
{
	SkipList<int,int> *s = new SkipList<int,int>(100,10,0.5);
 
	//创建
	cout<<"=========创建==========="<<endl;
 
	int a[] = {5,3,2,11,7,13,19,17,23};
 
	for(int i=0; i<9; i++)
	{
		s->Insert(a[i]);
	}
	s->Output();
 
	//搜索
	cout<<"=========搜索==========="<<endl;
	int k=17,e;
	cout<<"搜索元素k="<<k<<"如下:"<<endl;
	if(s->Search(17,e))
	{
		cout<<"位置搜索结果为:k="<<k<<",e="<<e;
	}
	cout<<endl;
 
	//删除
	cout<<"=========删除==========="<<endl;
	cout<<"删除跳跃表元素k="<<k<<"剩余元素如下:"<<endl;
	s->Delete(k,e);
	s->Output();
 
	delete s;
	return 0;
}
#include"time.h"
//随机数类
const unsigned long maxshort = 65536L;
const unsigned long multiplier = 1194211693L;
const unsigned long adder = 12345L;
 
class RandomNumber
{
	private:
		//当前种子
		unsigned long randSeed;
	public:
		RandomNumber(unsigned long s = 0);//构造函数,默认值0表示由系统自动产生种子
		unsigned short Random(unsigned long n);//产生0:n-1之间的随机整数
		double fRandom(void);//产生[0,1)之间的随机实数
};
 
RandomNumber::RandomNumber(unsigned long s)//产生种子
{
	if(s == 0)
	{
		randSeed = time(0);//用系统时间产生种子
	}
	else
	{
		randSeed = s;//由用户提供种子
	}
}
 
unsigned short RandomNumber::Random(unsigned long n)//产生0:n-1之间的随机整数
{
	randSeed = multiplier * randSeed + adder;//线性同余式
	return (unsigned short)((randSeed>>16)%n);
}
 
double RandomNumber::fRandom(void)//产生[0,1)之间的随机实数
{
	return Random(maxshort)/double(maxshort);
}

以上是关于c_cpp 如果用有序链表来表示一个含有Ñ个元素的有序集S,则在最坏情况下,搜索小号中一个元素需要O(n)的计算时间。提高有序链表效率的一个技巧是在有序链表的部分结点处增设附加指针以提高其搜的主要内容,如果未能解决你的问题,请参考以下文章

Java 实现有序链表

c_cpp 哈夫曼编码是广泛地用于数据文件压缩的​​十分有效的编码方法。其压缩率通常在20%〜90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。一个包含

Java单链表双端链表有序链表实现

LeetCode-链表复制带随机指针的链表

给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。

高频面试考点(考察分治法):合并k个排序链表