算法导论之链表

一、概念

(1)数组的线性序是由数组的下标决定的,链表中的顺序是由各对象中的指针所决定的

(2)链表结点结构

node *prev;

node *next;

int key;

(3)链表结点

node *head;

node *nil;//哨兵

(4)对链表的操作

LIST-SEARCH(L, k)

LIST-INSERT(L, x)

LIST-DELETE(L, x)

(5)哨兵是个哑对象,可以简化边界条件

二、代码

(1)没有哨兵的情况

[cpp] view plain copy

print?

  1. //链表结点结构
  2. struct node
  3. {
  4. node *pre;
  5. node *next;
  6. int key;
  7. //构造函数
  8. node(int x):pre(NULL),next(NULL),key(x){}
  9. };
  10. //链表结构
  11. struct List
  12. {
  13. node *head;
  14. List():head(NULL){}
  15. };
  16. //打印
  17. void List_Print(List *L)
  18. {
  19. node *p = L->head;
  20. while(p)
  21. {
  22. cout<<p->key<<‘ ‘;
  23. p = p->next;
  24. }
  25. cout<<endl;
  26. }
  27. //搜索,找出L中第一个关键字为k的结点,没有则返回NULL
  28. node *List_Search(List *L, int k)
  29. {
  30. node *x = L->head;
  31. while(x != NULL && x->key!=k)
  32. x = x->next;
  33. return x;
  34. }
  35. //插入
  36. void List_Insert(List *L, node *x)
  37. {
  38. //插入到表的前端
  39. x->next = L->head;
  40. if(L->head != NULL)
  41. L->head->pre = x;
  42. L->head = x;
  43. x->pre = NULL;
  44. }
  45. //删除
  46. void List_Delete(List *L, node* x)
  47. {
  48. if(x->pre != NULL)
  49. x->pre->next = x->next;
  50. else
  51. L->head = x->next;
  52. if(x->next != NULL)
  53. x->next->pre = x->pre;
  54. delete x;
  55. }
//链表结点结构
struct node
{
	node *pre;
	node *next;
	int key;
	//构造函数
	node(int x):pre(NULL),next(NULL),key(x){}
};
//链表结构
struct List
{
	node *head;
	List():head(NULL){}
};
//打印
void List_Print(List *L)
{
	node *p = L->head;
	while(p)
	{
		cout<<p->key<<' ';
		p = p->next;
	}
	cout<<endl;
}
//搜索,找出L中第一个关键字为k的结点,没有则返回NULL
node *List_Search(List *L, int k)
{
	node *x = L->head;
	while(x != NULL && x->key!=k)
		x = x->next;
	return x;
}
//插入
void List_Insert(List *L, node *x)
{
	//插入到表的前端
	x->next = L->head;
	if(L->head != NULL)
		L->head->pre = x;
	L->head = x;
	x->pre = NULL;
}
//删除
void List_Delete(List *L, node* x)
{
	if(x->pre != NULL)
		x->pre->next = x->next;
	else
		L->head = x->next;
	if(x->next != NULL)
		x->next->pre = x->pre;
	delete x;
}

(2)有哨兵的情况

[cpp] view plain copy

print?

  1. //链表结点结构
  2. struct node
  3. {
  4. node *pre;
  5. node *next;
  6. int key;
  7. //构造函数
  8. node(int x):pre(NULL),next(NULL),key(x){}
  9. };
  10. //链表结构
  11. struct List
  12. {
  13. node *nil;//哨兵
  14. List()
  15. {
  16. nil = new node(0);
  17. nil->next = nil;
  18. nil->pre = nil;
  19. }
  20. };
  21. //打印
  22. void List_Print(List *L)
  23. {
  24. node *p = L->nil->next;
  25. while(p != L->nil)
  26. {
  27. cout<<p->key<<‘ ‘;
  28. p = p->next;
  29. }
  30. cout<<endl;
  31. }
  32. //搜索,找出L中第一个关键字为k的结点,没有则返回NULL
  33. node *List_Search(List *L, int k)
  34. {
  35. node *x = L->nil->next;
  36. while(x != L->nil && x->key!=k)
  37. x = x->next;
  38. return x;
  39. }
  40. //插入
  41. void List_Insert(List *L, node *x)
  42. {
  43. //插入到表的前端
  44. x->next = L->nil->next;
  45. L->nil->next->pre = x;
  46. L->nil->next = x;
  47. x->pre = L->nil;
  48. }
  49. //删除
  50. void List_Delete(List *L, node* x)
  51. {
  52. x->pre->next = x->next;
  53. x->next->pre = x->pre;
  54. delete x;
  55. }
//链表结点结构
struct node
{
	node *pre;
	node *next;
	int key;
	//构造函数
	node(int x):pre(NULL),next(NULL),key(x){}
};
//链表结构
struct List
{
	node *nil;//哨兵
	List()
	{
		nil = new node(0);
		nil->next = nil;
		nil->pre = nil;
	}
};
//打印
void List_Print(List *L)
{
	node *p = L->nil->next;
	while(p != L->nil)
	{
		cout<<p->key<<' ';
		p = p->next;
	}
	cout<<endl;
}
//搜索,找出L中第一个关键字为k的结点,没有则返回NULL
node *List_Search(List *L, int k)
{
	node *x = L->nil->next;
	while(x != L->nil && x->key!=k)
		x = x->next;
	return x;
}
//插入
void List_Insert(List *L, node *x)
{
	//插入到表的前端
	x->next = L->nil->next;
	L->nil->next->pre = x;
	L->nil->next = x;
	x->pre = L->nil;
}
//删除
void List_Delete(List *L, node* x)
{
	x->pre->next = x->next;
	x->next->pre = x->pre;
	delete x;
}

三、练习

[cpp] view plain copy

print?

  1. 10.2-1
  2. 能,能
  3. 10.2-2
  4. //结点
  5. struct node
  6. {
  7. node *pre;//为了方便实现出栈操作
  8. node *next;
  9. int key;
  10. node(int x):pre(NULL),next(NULL),key(x){}
  11. };
  12. //链式栈
  13. struct list
  14. {
  15. node *Head;//栈的起始结点
  16. node *Top;//栈顶指针
  17. list(){Head = new node(0);Top = Head;}
  18. };
  19. //打印栈中的元素
  20. void Print(list *L)
  21. {
  22. node *p = L->Head->next;
  23. while(p)
  24. {
  25. cout<<p->key<<‘ ‘;
  26. p = p->next;
  27. }
  28. cout<<endl;
  29. }
  30. //入栈
  31. void Push(list *L, int x)
  32. {
  33. //构造一个新的结点
  34. node *A = new node(x);
  35. //链入到栈顶位置,修改指针
  36. L->Top->next = A;
  37. A->pre = L->Top;
  38. L->Top = A;
  39. }
  40. //出栈
  41. int Pop(list *L)
  42. {
  43. if(L->Head == L->Top)
  44. {
  45. cout<<"error:underflow"<<endl;
  46. return -1;
  47. }
  48. //取出栈顶元素
  49. int ret = L->Top->key;
  50. //修改指针
  51. node *A = L->Top;
  52. L->Top = A->pre;
  53. L->Top->next = NULL;
  54. delete A;
  55. return ret;
  56. }
  57. 10.2-3
  58. //结点
  59. struct node
  60. {
  61. node *next;
  62. int key;
  63. node(int x):next(NULL),key(x){}
  64. };
  65. //链式队列
  66. struct list
  67. {
  68. node *Head;//头指针
  69. node *Tail;//尾指针
  70. list(){Head = new node(0);Tail = Head;}
  71. };
  72. //打印
  73. void Print(list *L)
  74. {
  75. node *p = L->Head->next;
  76. while(p)
  77. {
  78. cout<<p->key<<‘ ‘;
  79. p = p->next;
  80. }
  81. cout<<endl;
  82. }
  83. //入队列
  84. void Enqueue(list *L, int x)
  85. {
  86. //构造一个新的结点
  87. node *A = new node(x);
  88. //链入尾部,修改指针
  89. L->Tail->next = A;
  90. L->Tail = A;
  91. }
  92. //出队列
  93. int Dequeue(list *L)
  94. {
  95. if(L->Head == L->Tail)
  96. {
  97. cout<<"error:underflow"<<endl;
  98. return -1;
  99. }
  100. //取出队头结点,修改指针
  101. node *A = L->Head->next;
  102. int ret = A->key;
  103. L->Head->next = A->next;
  104. if(A == L->Tail)
  105. L->Tail = L->Head;
  106. delete A;
  107. return ret;
  108. }
  109. 10.2-4
  110. 把哨兵的值置为一个不可能与x相等的值
10.2-1
能,能
10.2-2
//结点
struct node
{
	node *pre;//为了方便实现出栈操作
	node *next;
	int key;
	node(int x):pre(NULL),next(NULL),key(x){}
};
//链式栈
struct list
{
	node *Head;//栈的起始结点
	node *Top;//栈顶指针
	list(){Head = new node(0);Top = Head;}
};
//打印栈中的元素
void Print(list *L)
{
	node *p = L->Head->next;
	while(p)
	{
		cout<<p->key<<' ';
		p = p->next;
	}
	cout<<endl;
}
//入栈
void Push(list *L, int x)
{
	//构造一个新的结点
	node *A = new node(x);
	//链入到栈顶位置,修改指针
	L->Top->next = A;
	A->pre = L->Top;
	L->Top = A;
}
//出栈
int Pop(list *L)
{
	if(L->Head == L->Top)
	{
		cout<<"error:underflow"<<endl;
		return -1;
	}
	//取出栈顶元素
	int ret = L->Top->key;
	//修改指针
	node *A = L->Top;
	L->Top = A->pre;
	L->Top->next = NULL;
	delete A;
	return ret;
}
10.2-3
//结点
struct node
{
	node *next;
	int key;
	node(int x):next(NULL),key(x){}
};
//链式队列
struct list
{
	node *Head;//头指针
	node *Tail;//尾指针
	list(){Head = new node(0);Tail = Head;}
};
//打印
void Print(list *L)
{
	node *p = L->Head->next;
	while(p)
	{
		cout<<p->key<<' ';
		p = p->next;
	}
	cout<<endl;
}
//入队列
void Enqueue(list *L, int x)
{
	//构造一个新的结点
	node *A = new node(x);
	//链入尾部,修改指针
	L->Tail->next = A;
	L->Tail = A;
}
//出队列
int Dequeue(list *L)
{
	if(L->Head == L->Tail)
	{
		cout<<"error:underflow"<<endl;
		return -1;
	}
	//取出队头结点,修改指针
	node *A = L->Head->next;
	int ret = A->key;
	L->Head->next = A->next;
	if(A == L->Tail)
		L->Tail = L->Head;
	delete A;
	return ret;
}
10.2-4
把哨兵的值置为一个不可能与x相等的值

10.2-5

算法导论
10.2-5 环形链表实现字典操作INSERT、DELETE、SEARCH

10.2-6

使用带尾指针的链表,令A的尾指针为tail,tail->next=B

10.2-7

[cpp] view plain copy

print?

  1. //逆转
  2. void Reverse(list *L)
  3. {
  4. node *p = NULL, *q = L->Head, *r;
  5. //依次修改指针,让q是p->next,令q->next=p
  6. while(1)
  7. {
  8. r = q->next;
  9. q->next = p;
  10. if(r == NULL)
  11. {
  12. L->Head = q;
  13. break;
  14. }
  15. p = q;
  16. q = r;
  17. }
  18. }
时间: 2024-08-29 15:32:49

算法导论之链表的相关文章

【原创】《算法导论》链表一章带星习题试解——附C语言实现

原题: 双向链表中,需要三个基本数据,一个携带具体数据,一个携带指向上一环节的prev指针,一个携带指向下一环节的next指针.请改写双向链表,仅用一个指针np实现双向链表的功能.定义np为next XOR prev,请根据表头提供的信息,为双向链表编写插入函数.删除函数和查找函数,并在O(1)时间内实现链表的翻转. 分析: 问题的关键,在于怎样利用prev指针和next指针的异或结果,来获得上一节点或下一节点的地址值.也就是说,如何利用异或来算出具体的prev及next值.我们注意到两点: 1

【算法导论学习-23】两个单链表(single linked)求交点

问题:A.B两个单链表如果有交点,返回第一个交点在A中的位置(链表头结点位置为0). 分析:A.B如果有交点,交点的后继一定也是交点,所以一定是Y型相交,所以算法的思想如下 1)  求得A.B的长度,比如ALength,Blength 2)  判断ALength,Blength谁大,比如Alength>Blength 3)  Alength移动到Alength-Blength的位置,开始判断每个节点是否相等,相等则退出. 以本博客中"[算法导论学习-20]单链表(single linked

算法导论中对二叉树链表中 Delete 函数的实现

上一篇博客中对 Delete 函数的实现是根据被删除节点子节点的子节点个数, 分为无子节点, 一个子节点和两个子节点的情况分别考虑的. 而这次的代码是根据算法导论的实现用 C++ 直译过来的, 代码如下: void BinarySearchTree::Delete (const int32_t& value) { auto node = Search (value); if (node == nullptr) { cerr << "There is no such value

算法导论--图的遍历(DFS与BFS)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51897538 图的遍历就是从图中的某个顶点出发,按某种方法对图中的所有顶点访问且仅访问一次.为了保证图中的顶点在遍历过程中仅访问一次,要为每一个顶点设置一个访问标志.通常有两种方法:深度优先搜索(DFS)和广度优先搜索(BFS).这两种算法对有向图与无向图均适用. 以下面无向图为例: 1.深度优先搜索(DFS) 基本步骤: 1.从图中某个顶点v0出发,首先访问v

算法导论8:数据结构——栈 2016.1.8

栈在暑假的时候接触过了,当时还写了个计算器,用的中缀表达式后缀表达式的栈操作. http://www.cnblogs.com/itlqs/p/4749998.html 今天按照算法导论上的讲解规范了一下代码.主要是栈的初始化.判断空栈.入栈.出栈.遍历栈. #include<stdio.h> #define MAXTOP 10 struct _stack { int top; int num[MAXTOP+1]; }s; void init(struct _stack &S) { S.

红黑树&mdash;&mdash;算法导论(15)

1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极端情况是树变成了1条链)时,这些集合操作并不比在链表上执行的快.     于是我们需要构建出一种"平衡"的二叉搜索树.     红黑树(red-black tree)正是其中的一种.它可以保证在最坏的情况下,基本集合操作的时间复杂度是O(lgn). (2) 性质     与普通二叉搜索树不

算法导论-第24章 Dijkstra算法

Dikstra算法解决的是有向图上单源最短路径问题(无向图可以看成有相反的两条有向边),且要求边的权重都是非负值. 算法导论用了很多引理,性质来证明Dijstra算法的正确性,这里不说了,也表达不明白,只说我理解的过程. 有一个图G( V,E) ,选定一个源点s,维护一个集合Q=V-s,  Q中点有一个d值表示此时从s到该点的已知距离,s.d=0 :初始化都为正无穷,表明不可达.然后对s点所连接的点(设为点集M)进行松弛操作,就是设点m属于M, m.d > s.d+ w(s,m) 则更新 m.d

算法导论-二叉查找数

目录 引言 二叉查找树 节点定义 查找操作 插入操作 删除操作 二叉查找树存在问题 完整源码 讨论区 参考资料 内容                             1.引言                                   前面的文章介绍过二分查找.散列表查找:二分查找效率为Θ(lgn).二分查找要求数组是静态的,即元素不能动态的插入和删除,否则会耗费较多的时间:散列表查找效率可以到达Θ(1),但是一般用于“等于性查找“,不能进行“范围查找”;本文介绍的二叉查找树,(

算法导论 第13章 红黑树

二叉查找树的基本操作包括搜索.插入.删除.取最大和最小值等都能够在O(h)时间复杂度内实现,因此能在期望时间O(lgn)下实现,但是二叉查找树的平衡性在这些操作中并没有得到维护,因此其高度可能会变得很高,当其高度较高时,而二叉查找树的性能就未必比链表好了,所以二叉查找树的集合操作是期望时间O(lgn),最坏情况下为O(n). 红黑树也是一种二叉查找树,它拥有二叉查找树的性质,同时红黑树还有其它一些特殊性质,这使得红黑树的动态集合基本操作在最坏情况下也为O(lgn),红黑树通过给节点增加颜色和其它