CLRS 10.2链表
2015-11-28 08:47
260 查看
10.2-1
插入操作可以,删除操作不能,除非你给出要删除对象的前一个指针。
10.2-2
不带头结点的单链表,在头部插入和删除就可以实现栈。
10.2-3
出队的时候在头部删除,入队的时候在尾部插入,需要在尾部添加一个指针以记录尾部。
10.2-4
将哨兵的值设为 kk。
10.2-5
采用带头结点的循环链表,对
10.2-6
使用双链表,把第一个链表的尾结点和第二个链表的第一个结点相连。
10.2-7
使用头插法即可实现逆转。代码为带头结点的循环单链表。
10.2-8
首先,需要知道异或的性质,我们根据 npnp 的定义有 np[x]=next[x]np[x] = next[x] XOR prev[x] prev[x],再由异或的性质有 next[x]=np[x]next[x] = np[x] XOR prev[x],prev[x]=next[x]prev[x],prev[x] = next[x] XOR np[x] np[x]。也就是说,如果我们知道本结点的下一个结点的地址,我们就能算出本结点的上一个结点地址,反之,知道上一个结点地址就知道下一个结点的地址。
对于在 O(1)O(1) 的时间内逆转,我们添加两个指针,分别指向头和尾,逆转的时候只需交换头指针和尾指针即可。
代码如下,感觉第一次会有点不可理解,在
插入操作可以,删除操作不能,除非你给出要删除对象的前一个指针。
10.2-2
不带头结点的单链表,在头部插入和删除就可以实现栈。
#include <iostream> using std::cout; using std::endl; struct list_t { int key; list_t *next; }; void push(list_t **list,int key) { list_t *node = new list_t; node->next = *list; node->key = key; *list = node; } int pop(list_t **list) { if(*list == NULL) { cout << "List is Empty" << endl; return -1; } int ret = (*list)->key; list_t *node = *list; *list = (*list)->next; delete node; return ret; } void print(list_t *list) { while(list != NULL){ cout << list->key << ' '; list = list->next; } } int main() { list_t *list = NULL; push(&list,8); push(&list,5); push(&list,3); pop(&list); print(list); return 0; }
10.2-3
出队的时候在头部删除,入队的时候在尾部插入,需要在尾部添加一个指针以记录尾部。
10.2-4
将哨兵的值设为 kk。
LIST-SEARCH'(L, k): x = L.nil.next L.nil.key = k while x.key ≠ k x = x.next return x
10.2-5
采用带头结点的循环链表,对
SEARCH采用练习10.2-4中的方法,代码如下:
#include <iostream> using std::cout; using std::endl; struct node_t { int key; node_t *next; }; struct list_t { node_t nil; }; void init(list_t *list) { list->nil.key = 0; list->nil.next = &(list->nil); } node_t *SEARCH(list_t *list, int key) { node_t *node = list->nil.next; list->nil.key = key; while(node->key != key) node = node->next; if(node == &(list->nil)) return NULL; else return node; } void INSERT(list_t *list, int key) { node_t *node = new node_t; node->key = key; node->next = list->nil.next; list->nil.next = node; } void DELETE(list_t *list,int key) { node_t *node = &(list->nil); while(node->next != &(list->nil)) { if(node->next->key == key) { node_t *del = node->next; node->next = node->next->next; delete del; } else node = node->next; } } int main() { list_t head,*list = &head; init(list); INSERT(list,8); INSERT(list,3); INSERT(list,7); node_t *node = SEARCH(list,3); if(node != NULL) cout << node->key << endl; else cout << "not exist" << endl; DELETE(list,3); node = SEARCH(list,3); if(node != NULL) cout << node->key << endl; else cout << "not exist" << endl; return 0; }
10.2-6
使用双链表,把第一个链表的尾结点和第二个链表的第一个结点相连。
10.2-7
使用头插法即可实现逆转。代码为带头结点的循环单链表。
#include <iostream> using std::cout; using std::endl; struct node_t { int key; node_t *next; }; struct list_t { node_t nil; }; void init(list_t *list) { list->nil.key = 0; list->nil.next = &(list->nil); } node_t *SEARCH(list_t *list, int key) { node_t *node = list->nil.next; list->nil.key = key; while(node->key != key) node = node->next; if(node == &(list->nil)) return NULL; else return node; } void INSERT(list_t *list, int key) { node_t *node = new node_t; node->key = key; node->next = list->nil.next; list->nil.next = node; } void DELETE(list_t *list,int key) { node_t *node = &(list->nil); while(node->next != &(list->nil)) { if(node->next->key == key) { node_t *del = node->next; node->next = node->next->next; delete del; } else node = node->next; } } void REVERSE(list_t *list) { node_t *node = list->nil.next; list->nil.next = &(list->nil); while(node != &(list->nil)) { node_t *next = node->next; node->next = list->nil.next; list->nil.next = node; node = next; } } int main() { list_t head, *list = &head; init(list); INSERT(list,8); INSERT(list,4); INSERT(list,2); INSERT(list,10); INSERT(list,-5); REVERSE(list); return 0; }
10.2-8
首先,需要知道异或的性质,我们根据 npnp 的定义有 np[x]=next[x]np[x] = next[x] XOR prev[x] prev[x],再由异或的性质有 next[x]=np[x]next[x] = np[x] XOR prev[x],prev[x]=next[x]prev[x],prev[x] = next[x] XOR np[x] np[x]。也就是说,如果我们知道本结点的下一个结点的地址,我们就能算出本结点的上一个结点地址,反之,知道上一个结点地址就知道下一个结点的地址。
对于在 O(1)O(1) 的时间内逆转,我们添加两个指针,分别指向头和尾,逆转的时候只需交换头指针和尾指针即可。
代码如下,感觉第一次会有点不可理解,在
INSERT里面注释了不少,能理解
INSERT应该就可以理解全部代码了。
#include <iostream> using std::cout; using std::endl; struct node_t { int key; node_t *np; }; struct list_t { node_t *head; node_t *tail; }; void init(list_t *list) { list->head = NULL; list->tail = NULL; } void INSERT(list_t *list,int key) { node_t *node = new node_t; node->key = key; /********** node->np = node->next ^ node->prev *********** ***每次插入一个节点的时候,node->next为空,node->prev就是尾指针指向的节点*/ node->np = (node_t *)(NULL ^ (unsigned)(list->tail)); /*** 插入后节点后就需要修改原先的尾节点的np值,也就是尾指针指向的节点的np ****** **** list->tail->np = list->tail->np->next ^ list->tail->np->prev ****** **** list->tail->np->next等于新插入节点地址,即node,list->tail->np->prev又需要继续异或 ****** **** list->tail->np->prev = (后节点 ^ 自身),分别为 NULL,list->tail->np ******/ if(list->tail) list->tail->np = (node_t *)((unsigned)node ^ (NULL ^ (unsigned)(list->tail->np))); if(!list->head) //头指针为空,修改头指针的指向 list->head = node; list->tail = node; //修改头指针的指向 } node_t *SEARCH(list_t *list, int key) { node_t *node = list->head; node_t *prev = NULL; node_t *next; while(node) { if(node->key == key) return node; next = (node_t *)((unsigned)(node->np) ^ (unsigned)(prev)); prev = node; node = next; } return NULL; } void DELETE(list_t *list,int key) { node_t *node = list->head; node_t *prev = NULL; node_t *next; while(node) { if(node->key == key) { next = (node_t *)((unsigned)(node->np) ^ (unsigned)(prev)); if(prev) //删除的不是第一个节点 prev->np = (node_t *)((unsigned)(prev->np) ^ (unsigned)(node) ^ (unsigned)(next)); else list->head = next; //修改头指针 if(next) next->np = (node_t *)((unsigned)(next->np) ^ (unsigned)(node) ^ (unsigned)(prev)); else list->tail = prev; node = next; } else { next = (node_t *)((unsigned)(node->np) ^ (unsigned)(prev)); prev = node; node = next; } } } void REVERSE(list_t *list) { node_t *temp; temp = list->head; list->head = list->tail; list->tail = temp; } void PRINT(list_t *list) { node_t *node = list->head; node_t *prev = NULL; node_t *next; while(node) { cout << node->key << ' '; next = (node_t *)((unsigned)(node->np) ^ (unsigned)(prev)); prev = node; node = next; } } int main() { list_t Head, *list = &Head; init(list); INSERT(list,8); INSERT(list,0); INSERT(list,-6); INSERT(list,2); INSERT(list,-7); PRINT(list); cout << endl; REVERSE(list); PRINT(list); cout << endl; DELETE(list,2); DELETE(list,-7); PRINT(list); return 0; }
相关文章推荐
- 记一次:c3p0连接池死锁的问题
- 被指“造假” 京东喊冤 到底谁在卖“真褚橙”?
- 2015 11 27编写JAVA程序
- 编译原理(三) 消除文法的左递归
- 世界上最精彩的是文字,最有价值的地方是人迹罕至之处。
- 集成入鼠标右键,删除.svn信息
- iOS开发之UINavigationController(二)
- css中position属性(absolute|relative|static|fixed)解析
- [LeedCode]Sparse Matrix Multiplication
- Codeforces 52C (线段树区间更新)
- Android Demo 下拉刷新+加载更多+滑动删除
- Android Demo 下拉刷新+加载更多+滑动删除
- ListView控件的不为人知的秘密
- 对与java io知识的部分总结
- 又一次的Hello World
- 电子流水灯-20151116
- 课件_53.第九章:Ajax技术[8]-全局Ajax设置、辅助方法.rar,很常用
- WebDatagrid自学笔记一
- 实践很重要,但更重要的是实践之后的反省
- 课件_52.第九章:Ajax技术[7]-$.ajax方法.rar,很常用