现在的位置: 首页 > 综合 > 正文

算法导论 10.2-8 用一个指针实现双链表

2013年08月13日 ⁄ 综合 ⁄ 共 2116字 ⁄ 字号 评论关闭

一、题目

说明如何对每个元素仅用一个指针np[x](而不是两个指针next和prev)来实现双链表。假设所有指针值都是k位的整型数,且定义np[x] = next[x] XOR prev[x],即next[x]和prev[x]的k位异或(NIL用0表示)。注意要说明访问表头所需的信息,以及如何实现在该表上的SEARCH、INSERT和DELETE操作。如何在O(1)时间内实现这样的表。

二、思路

np[x] = next[x] XOR prev[x],根据异或的性质,next[x] = np[x] XOR prev[x],prev[x] = next[x] XOR np[x],只要知道这个结点的下一个结点的地址,就能求出它上一个结点的地址,或者,只要知道这个结点上一个结点的位置,就知道求出它的下一个结点的位置

在链表中定义一个头结点,这个结点的位置是已知的,根据上文的结论,就可以依次遍历链表中的每个结点,进行于SEARCH、INSERT和DELETE操作了

三、代码

 

#include <iostream>
#include <string>
using namespace std;

//结点
struct node
{
	int key;//值
	unsigned int np;//指针,地址是32位的,所以要用无符号整数表示
	node(int k):key(k),np(0){}
};
//链表
struct list
{
	node head;//头结点,作为哨兵,用于寻找第一个结点
	list():head(0){}
};
//插入操作
void Insert(list *l, int k)
{
	//生成一个新的结点
	node *A = new node(k);
	//要插入到链表的第一个位置,即head->next处
	//A->next是head->next,其地址为l->head.np,A->prev是head,其地址为(unsigned int)(&(l->head))
	//A->np是A->next ^ A->prev
	A->np = l->head.np ^ (unsigned int)(&(l->head));
	//若原链表不为空,则要修改原head->next结果的指针,因为它的prev发生了改变
	node *p = (node*)l->head.np;
	if(p)
	{
		//NewNp = OldNp ^ OldNext ^ OldPrev ^ NewNext ^ NewPrev;
		//在这里,只是p->prev有改动,p->next不变,因此简化为NewNp = OldNp ^ OldPrev ^ NewPrev;
		//OldPrev是Head,其地址为(unsigned int)(&(l->head)),NewPrev是新结点A,其地址为(unsigned int)A
		unsigned int temp = p->np;
		temp = temp ^ (unsigned int)A ^ (unsigned int)(&(l->head));
		p->np = temp;
	}
	l->head.np = (unsigned int)A;
}
//输出链表
void Print(list *l)
{
	//找到第一个结点的位置,因为Head->prev=0,Head->next=Head->np,直接可以得到第一个结点的位置
	unsigned int p = l->head.np, q;
	//q表示为p->prev结点的位置
	q = (unsigned int)(&(l->head));
	//把p转换为指针
	while((node*)p)
	{
		//输出
		cout<<((node*)p)->key<<' ';
		//p指向下一个元素
		unsigned int t = p;
		p = ((node*)p)->np ^ q;
		q = t;
	}
	cout<<endl;
}
//删除
void Delete(list *l, int k)
{
	//依次遍历每个元素,遍历方法同Search 
	unsigned int p = l->head.np, q;
	q = (unsigned int)(&(l->head));
	while((node*)p)
	{
		if(((node*)p)->key == k)
			break;
		unsigned int t = p;
		p = ((node*)p)->np ^ q;
		q = t;
	}
	//p是待删除元素的地址,q是待删除元素的上一个元素的地址,r是待删除元素的下一个元素的地址
	if((node*)p == NULL)
		return;
	int r = ((node*)p)->np ^ q;
	//修改q->next和修改r->prev,修改方法与INSERT中的修改方法相似
	((node*)q)->np = ((node*)q)->np ^ p ^ r;
	if((node*)r != NULL)
		((node*)r)->np = ((node*)r)->np ^ p ^ q;
	//删除p指向的结点
	delete (node*)p;
}
int main()
{
	string str;
	list *L = new list;
	int x;
	while(1)
	{
		cin>>str;
		if(str == "P")
		{
			Print(L);
		}
		else if(str == "I")
		{
			x = rand() % 100;
			cout<<x<<endl;
			Insert(L, x);
		}
		else if(str == "D")
		{
			cin>>x;
			Delete(L, x);
		}
	}
	return 0;
}

 

抱歉!评论已关闭.