算法导论习题(10)

10.2-8 说明如何在每个元素仅使用一个指针x.np的(而不是通常的两个指针next和pre)情况下实现双向链表,假设所有的指针的值都可以视为k位的整型数,且定义x.np = x.next ^ x.pre,即 x.next 和 x.pre 的异或,(NULL的值为0)注意要说明获取表头所需的信息,并说明如何在该表上实现SEARCH、INSERT、DELETE和REVERSE,REVERSE要求时间复杂度为:O(1)。

需要了解的是异或运算的特点:a = b ^ c,则:b = a ^ c,c = a ^ b。

算法实现上,要注意的是如果要将指针地址转换为整型数,不能简单的使用int,因为在32位机上地址为4字节,64位机上为8字节,所以应当根据自己操作系统的硬件情况选择使用int还是long。(目前为止,下面的代码地址转换还是存在问题,之后纠正) 

*出现的问题:

1)地址问题,不应该使用&取地址符,这样得到的是物理地址的值,而不是逻辑地址,导致本应使用NULL的逻辑0地址变成了物理地址;

2)new操作,在测试函数中使用它导致每次都会申请到同一个地址,而且这个地址应该是在脱离函数以后就被释放了;

3)当我尝试把新的Node的指针申请放在main函数中时,插入没有问题,但是在SHOW函数执行的时候,出现"error: segment fault 11",似乎是不能访问;

4)循环处的问题,pre不能直接在cur之前重新赋值,修改成这样:

temp = cur;
cur = (Node*) ((long)(cur->np) ^ (long)pre);
pre = cur;

主要代码(不包括以上修改):

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <ctime>

using namespace std;

struct Node {
	int value;
	Node* np;
};

// define class: LIST
class LIST {
private:
	Node* head;
	Node* tail;

public:
	LIST();
	void INSERT(int);
	void DELETE(int);
	Node* SEARCH(int);
	void REVERSE();
	void SHOW();
};

// construct
LIST::LIST() {
	head = NULL;
	tail = NULL;
}

// insertion
void LIST::INSERT(int val) {
	printf("begin-INS\n");
	Node* p = new Node();
	p->value = val;

	if (head != NULL) {
		head->np = (Node*)((long)&(head->np) ^ (long)&p);  // modify the old head's np
	}

	// new head: modify its np (head->np ^ 0), 
	// and the first elem's np = 0, in other words, its next ptr = NULL
	p->np = head;  
	head = p;
	if (tail == NULL) {
		tail = p;  // jump the origin head, ignore it
	}
	delete p;
	printf("end-INS\n");
}

// deleting
void LIST::DELETE(int val) {
	printf("begin-DEL\n");
	Node* cur = head;
	Node* pre = NULL;

	while (cur != NULL && cur->value != val) {
		pre = cur;
		cur = (Node*) ((long)&(cur->np) ^ (long)&pre);
	}

	if (NULL == cur) {
		printf("Cannot find this value!\n");
	} else {
		// delete this value's Node
		Node* next = (Node*) ((long)&pre ^ (long)&(cur->np));
		Node* ppre = (Node*) ((long)&(pre->np) ^ (long)&cur);
		pre->np = (Node*) ((long)&ppre ^ (long)&next);
	}
	printf("end-DEL\n");
}


// searching
Node* LIST::SEARCH(int val) {
	printf("begin-SEAR\n");
	Node* cur = head;
	Node* pre = NULL;
	while (cur != NULL && cur->value != val) {
		pre = cur;
		cur = (Node*) ((long)&(cur->np) ^ (long)&pre);
	}
	printf("end-SEAR\n");
	return cur;
}

// reversing
void LIST::REVERSE() {
	Node* temp = head;
	head = tail;
	tail = temp;
}

void LIST::SHOW() {
	Node* cur = head;
	Node* pre = NULL;

	while (cur != NULL) {
		printf("%d, ", cur->value);
		pre = cur;
		cur = (Node*) ((long)pre ^ (long)cur->np);
	}
	printf("\n");
}

// test func
void test() {
	LIST L;
	for (int i = 0; i < 10; i++) {
		L.INSERT(i + 3);
	}
	L.SHOW();

	Node* node = L.SEARCH(4);
	if (node != NULL) {
		printf("%d\n", node->value);
	} else {
		puts("This value 4 is not exist!");
	}

	Node* node2 = L.SEARCH(100);
	if (node2 != NULL) {
		printf("%d\n", node2->value);
	} else {
		puts("This value 100 is not exist!");
	}

	L.REVERSE();
	L.SHOW();
	
}
int main() {
	test();
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值