算法导论习题(10)
2016-08-21 21:33
288 查看
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;
主要代码(不包括以上修改):
需要了解的是异或运算的特点: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; }
相关文章推荐
- 算法导论习题5.1-3
- <算法导论习题>2.2-2
- 算法导论2.3-7习题
- 算法导论2:几个习题 2016.1.2
- 算法竞赛入门经典 习题2-10 排列(permutation)
- 算法导论程序10--建堆(Python)
- 算法导论第三版习题5.2
- 算法导论2-4习题解答(合并排序算法)
- 算法导论——lec 10 图的基本算法及应用
- Introduction to Algorithms 算法导论 第3章 函数的增长 学习笔记及习题解答
- 算法导论10(基本数据结构)
- 算法导论10.1-6习题解答(用两个栈实现一个队列)
- 【算法导论(第三版)】第二章部分习题代码
- Introduction to Algorithms 算法导论 第4章 递归式 学习笔记及习题解答
- 链表的多重数组表示(算法导论10-3)
- 算法导论10.1-7习题解答(用两个队列实现一个栈)
- 算法导论6.1-2习题解答
- 算法导论10.1-6习题解答(用两个栈实现一个队列)
- 算法导论第六章习题答案(第三版) Introduction to Algorithm
- 算法导论第十二章习题12.3-1---二叉树插入的递归版本