1. 编写一个程序,把一个有序整数数组放到二叉树中。
2. 从顶部开始逐层打印二叉树节点。
3. 设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度不能为O(n2)。
4. 二叉排序树中,令f = (最大值+最小值) / 2,设计一个算法,找出距离f值最近、大于f值的结点。复杂度不能为O(n2)。
5. 有双向循环链表结点定义为:
struct node
{
int data;
struct node *front,*next;
};
有两个双向循环链表A,B,知道其头指针为:pHeadA、pHeadB,请写一函数将两链表中data值相同的结点删除。
6. 输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
7. 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。
10
/ \
6 14
/ \ / \
4 8 12 16
转换成双向链表
4=6=8=10=12=14=16
首先我们定义的二元查找树 节点的数据结构如下:
struct BSTreeNode
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
8. 定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。
9. 输入一个整数和一棵二元树。从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。
打印出和与输入整数相等的所有路径。
例如:输入整数22和如下二元树
10
/ \
5 12
/ \
4 7
则打印出两条路径:10, 12和10, 5, 7
二元树节点的数据结构定义为:
struct BinaryTreeNode // a node in the binary tree
{
int m_nValue; // value of node
BinaryTreeNode *m_pLeft; // left child of node
BinaryTreeNode *m_pRight; // right child of node
};
10. 给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。为了简化问题,我们假设俩个链表均不带环。
问题扩展:
(1) 如果链表可能有环列?
(2) 如果需要求出俩个链表相交的第一个节点列?
11. 输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。
例如:输入5、7、6、9、11、10、8,由于这一整数序列是如下树的后序遍历结果:
8
/ \
6 10
/ \ / \
5 7 9 11
因此返回true。
如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。
12. 如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数。
写一个程序,求一棵二叉树中相距最远的两个节点之间的距离。
13. 输入一个单向链表,输出该链表中倒数第k个结点。链表的倒数第0个结点为链表的尾指针。
链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
14. 输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。
用递归和循环两种方法完成树的镜像转换。
定义二元查找树的结点为:
struct BSTreeNode
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
15. 求一个二叉树中任意两个节点间的最大距离,两个节点的距离的定义为这两个节点间边的个数。
比如:某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复杂度。
16. 求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边,有向图不再连通,描述算法。
17. 请修改append函数,利用这个函数实现:
两个非降序链表的并集,1->2->3 和 2->3->5 并为 1->2->3->5
另外只能输出结果,不能修改两个链表的数据。
18. 递归和非递归俩种方法实现二叉树的前序遍历。
19. 输入一棵二元树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
二元树的结点定义如下:
struct SBinaryTreeNode // a node of the binary tree
{
int m_nValue; // value of node
SBinaryTreeNode *m_pLeft; // left child of node
SBinaryTreeNode *m_pRight; // right child of node
};
20. 用俩栈实现队列,某队列的声明如下:
template<typename T> class CQueue
{
public:
CQueue() {}
~CQueue() {}
void appendTail(const T& node); // append a element to tail
void deleteHead(); // remove a element from head
private:
T m_stack1;
T m_stack2;
};
21. 给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
函数的声明如下:void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted);
22. 两个单向链表,找出它们的第一个公共结点。
链表的结点定义为:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
23. 用递归颠倒一个栈。例如输入栈{1, 2, 3, 4, 5},1在栈顶。颠倒之后的栈为{5, 4, 3, 2, 1},5处在栈顶。
24. 二叉树的结点定义如下:
struct TreeNode
{
int m_nvalue;
TreeNode* m_pLeft;
TreeNode* m_pRight;
};
输入二叉树中的两个结点,输出这两个结点在树中最低的共同父结点。
25. 有一个复杂链表,其结点除了有一个m_pNext指针指向下一个结点外,还有一个m_pSibling指向链表中的任一结点或者NULL。
其结点的C++定义如下:
struct ComplexNode
{
int m_nValue;
ComplexNode* m_pNext;
ComplexNode* m_pSibling;
};
下图是一个含有5个结点的该类型复杂链表。
图中实线箭头表示m_pNext指针,虚线箭头表示m_pSibling指针。为简单起见,指向NULL的指针没有画出。
请完成函数ComplexNode* Clone(ComplexNode* pHead),以复制一个复杂链表。
26. 给定单链表、检测是否有环。要求:时间复杂度为O(n),空间复杂度为O(1)。
27. 给定两个单链表(head1, head2),检测两个链表是否有交点,如果有返回第一个交点。
28. 给定单链表(head),如果有环的话请返回从头结点进入环的第一个节点。
29. 只给定单链表中某个结点p(并非最后一个结点,即p->next!=NULL)指针,删除该结点。
30. 只给定单链表中某个结点p(非空结点),在p前面插入一个结点。
31. 输入两个整数序列。其中一个序列表示栈的push顺序,判断另一个序列有没有可能是对应的pop顺序。
为了简单起见,我们假设push序列的任意两个整数都是不相等的。
比如,输入的push序列是1, 2, 3, 4, 5,那么4, 5, 3, 2, 1就有可能是一个pop系列。因为可以有如下的push和pop序列:push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,这样得到的pop序列就是4, 5, 3, 2, 1。但序列4, 3, 5, 1, 2就不可能是push序列1, 2, 3, 4, 5的pop序列。
32. 编写实现链表排序的一种算法。说明为什么你会选择用这样的方法?
33. 编写实现数组排序的一种算法。说明为什么你会选择用这样的方法?
34. 怎样编写一个程序,把一个有序整数数组放到二叉树中?
35. 输入一棵二叉树的根结点,判断该树是不是平衡二叉树。
36. 输入两棵二叉树A和B,判断树B是不是A的子结构。
例如,下图中的两棵树A和B,由于A中有一部分子树的结构和B是一样的,因此B就是A的子结构。
1 8
/ \ / \
8 7 9 2
/ \
9 2
/ \
4 7