- 比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?
(1)空间上的比较,
顺序表是一段连续空间,然后实现数据的增删,顺序表一般是固定大小的,链表是每次之开辟一个节点的大小用多少给多少。
(2)空间的使用
顺序表是直接开辟一段空间,如果数据过少的话就会造成空间的浪费,而链表是需要存储一个数据才开辟一个节点的空间,来保存数据,虽然有一个非数据项的指针域占用空间,可是相比顺序表要好很多,然而当我们知道存储的数据的数量时,用顺序表来开辟空间,用顺序表来存储完全不会浪费空间,因为顺序表是连续的一段空间,而使用链表时,每个节点都有指针域占用空间,就会造成空间的浪费,而且链表的分配内存是随机的,多次申请之后会把这片空间高的七零八碎,可能还会出现一些很小用不到的碎片空间,这样就会造成很大的空间浪费,而使用顺序表不需要经常申请空间,这样就减少了碎片空间的存在,一定程度上就节省了空间
(3)对CPU高速缓存的影响
由于顺序表的空间是连续开辟的,而且会一次开辟多个元素的空间,所以使用顺序表时可以一次性把多个数据写入高速缓存再写入主存,顺序表的CPU高速缓存效率更高,且CPU流水线不容易被打断;而链表是每需要存储一个数据才开辟一片空间,每个数据都需要单独写入高速缓存,然后写入主存,链表的CPU高速缓存效率更低,CPU流水线容易被打断
(4)访问效率
顺序表的结构类似于数组支持随机访问,可利用下标直接随机访问,链表不支持随机访问,要想访问只能遍历整个链表,顺序表随机访问的平均时间复杂度是O(1)链表的访问的平均时间复杂度是O(n)
(5)随机位置插入和删除效率
顺序表随机位置插入数据时需要将要插入位置的后面元素全部向后搬移,然后留出空位才能进行插入,删除的时候,需要将后面的元素全不向前搬移,而链表存储元素时只需要改变链表的前驱后继的指针指向即可,顺序表随机插入删除的平均时间复杂度是O(n),链表随机插入删除的平均时间复杂度是O(1)。
使用场景:
主要关心随机访问的话就使用顺序表,主要关心随机位置插入删除的话,使用链表。
2. 从尾到头打印单链表
这里采用递归思路,链表节点分别是1,2,3,4,5
如果头结点为空直接返回,这里是递归的出口,如果不为空递归打印下一个节点,直到最后打印信息,一层层返回并打印节点信息,实现逆序打印,原理很简单,这里用一个三个节点的链表来演示一下:
- 删除一个无头单链表的非尾节点(不能遍历链表)
因为不能遍历链表所以我们不能遍历链表找它的前一个节点,但是我们直到这个节点不是尾节点,意味着它的下一个节点必不为空,我们可以直接找到它的下一个节点,然后把下一个节点的数据域和指针域值都赋给当前要删的这个节点,然后删去要删节点的下一个节点,也能起到删除这个节点的作用。
- 在无头单链表的一个非头节点前插入一个节点
我们最先想到的办法就是从前往后遍历找到这个节点的前一个,将新节点插在这个节点之后,但是作为一个面试题肯定不可能这么简单,所以我们采用另一种方式,我们知道当前节点虽然在前面插有点困难但是在它后面插入一个节点,对于我们来说还是很简单的,我们先将这个新节点插入到这个节点之后,但是排列的顺序明显不是我们想要的,有什么区别呢,无非就是已知节点和插入节点的顺序搞反了,所以我们把两个节点的数据域交换一下,就能得到想要的结果了。
- 单链表实现约瑟夫环(JosephCircle)
首先来介绍一下什么是约瑟夫环吧,这是一个数学问题,n个人围坐在圆桌旁,依次报数,数到m的人出列直到所有人都出列。
首先的把单链表设计成一个环,然后定义一个计数器,从1开始,每经过一个节点++一次,计数器和n作比较如果相等就说明找到要出列的节点,将节点的数字输出,并将计数器置为1,继续循环,删除的时候分为两种情况一种是有两个及以上节点的,采用删除链表的非尾节点的方式,如果只有一个节点直接将节点释放,并置成空,结束。
- 逆置/反转单链表
定义三个指针,pPre表示前一个节点,初始值为空,pcur指向当前节点,pNext指向下一个节点,设置一个循环,循环条件pcur->next不为空,也就是走到最后一个节点然后停下来,每次进入循环,pcur的next指向pPre,然后pPre走到当前节点的位置,保存当前节点信息,pcur走到pNext位置,这里因为pcur和pNext之间的关系已经断了所以只能采用赋值方式,然后pNext往后走,一直到最后一个节点,因为走到最后节点直接就退出了没有指向前一个节点,所以这里先把当前节点的next指向前一个节点,然后把当前节点设为新的链表头部
- 单链表排序(冒泡排序&快速排序)
在这里我们用到了STL中的容器vector,先将节点都放进容器中,然后就可以对链表按照数组一样进行访问了,这里排序的实质就是把它们的数据域排序了一下,也能得到相同结果,这里使用冒泡排序和快排进行排序两种方法,其他排序方法也是可以的。 - 合并两个有序链表,合并后依然有序
就如图所示两个链表进行合并,首先将较小的一个作为新链表的头,也就是0的位置然后比较,0后面的和另一个链表的第一个的大小,把小得插入到0后面,以后每次都是做相同的事,每次比较最前面两个把小得放在链表的下一节点,直到两个链表有一个为空,递归结束。
- 查找单链表的中间节点,要求只能遍历一次链表
定义两个节点一个快节点另一个慢节点,慢节点一次走一步,快节点一次走两步,这样快节点走到末尾的时候,慢节点的位置就是中间节点的位置。
- 查找单链表的倒数第k个节点,要求只能遍历一次链表
同样定义两个指针,first指针先走k步,然后两个指针一起走,当first指针走到空的时候,刚好second的位置就是倒数第k个节点的位置
- 删除链表的倒数第K个结点
首先利用上面的方法找到倒数第k个节点,然后判断这个节点是不是空,是空的话没有办法删除,直接返回,如果不是空的话,分两种情况,待删除节点的下一个节点是不是空,不是空的话,把它下一个节点的数据域和指针域都交给待删除节点,然后删除待删除节点的下一个节点;不是的话,直接调用PopBack函数。 - 判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复杂度&空间复杂度。
用于测试的单链表如图所示,我们定义两个指针,一个一次走一步,一个一次走两步,如果不带环的话,快的指针就会走到空的位置,如果带环的话,快的两个指针就会在环中一直死循环,但是由于一个指针走的块一个指针走的慢两个指针总会相遇,按照这种算法相遇的点刚好就是入口点,我们知道入口点之后,就可以定义一个指针从入口点开始回到入口点走一圈,就可以统计出环中的长度。时间复杂读O(n)空间复杂度:O(1)
- 判断两个链表是否相交,若相交,求交点。(假设链表不带环)
如图所示,当两个单链表相交时,它们从交点开始都是相同的。但是两个链表可能长短不一样,我们让长的链表先走比短的链表多的步数,然后两个一起往后走,如果相交一定的会相交,否则会走到空。 - 判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
这里的条件是可能带环,我们先求两个链表是不是带环,两个都不带环就用上面那种方式去处理,一个带环一个不带环是不可能相交的,直接返回,两个都带环说明是两个链表共用一个环,我们可以求出两个带环链表的入口点,然后固定一个入口点让另外一个入口点在环内去找这个入口点,如果经过一圈还没找到,说明两个链表不相交,否则说明两条链表相交。 - 复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。
我们一共分为三步,也分别用三个函数来实现,我们首先遍历原链表,将每个节点拷贝之后再插入到该节点的后面,所有的节点都执行这种操作;接下来对随机域进行处理,遍历链表原链表的随机域指向哪里,对应的它后面的拷贝节点(红色)的随机域就指向,该节点的随机域指向节点的下一个位置。第三步,将拷贝的节点和原节点进行分离,并将新拷贝的链表的头返回,复制复杂链表完成。 - 求两个已排序单链表中相同的数据。void UnionSet(Node* l1, Node* l2);
这里我的算法思路是遍历两个链表每次判断前面两个节点的数据域大小,如果相等输出值两个都向后走,不相等的话就让小得先走,由于链表都是有序的,这样就可以求出交集,当任何一条链表走到空的位置就结束。
代码如下:
#include<stdio.h>
#include<malloc.h>
#include<vector>
typedef struct Node
{
struct Node* _next;
int _data;
}node_t;
typedef node_t* pNode;
pNode head = NULL;
pNode head1 = NULL;
void PushBack(int data)
{
pNode pNewNode = (pNode)malloc(sizeof(node_t));
pNewNode->_data = data;
pNewNode->_next = NULL;
if (head == NULL)
head = pNewNode;
else
{
pNode pcur = head;
while (pcur->_next)
{
pcur = pcur->_next;
}
pcur->_next = pNewNode;
}
}
void PopBack()
{
if (head == NULL)
return;
pNode pcur = head;
pNode ppre = NULL;
while (pcur->_next)
{
ppre = pcur;
pcur = pcur->_next;
}
ppre->_next = NULL;
free(pcur);
pcur = NULL;
}
void PushFront(int data)
{
pNode pNewNode = (pNode)malloc(sizeof(node_t));
pNewNode->_data = data;
pNewNode->_next = NULL;
if (head == NULL)
head = pNewNode;
else
{
pNewNode->_next = head;
head = pNewNode;
}
}
void PopFront()
{
if (head == NULL)
return;
pNode pDel = head;
head = head->_next;
free(pDel);
pDel = NULL;
}
void Display()
{
if (head == NULL)
return;
pNode pcur = head;
while (pcur)
{
printf("%d ", pcur->_data);
pcur = pcur->_next;
}
printf("\n");
}
//2. 从尾到头打印单链表
void DisplayReverse(pNode pCur)
{
if (pCur == NULL)
return;
DisplayReverse(pCur->_next);
printf("%d ", pCur->_data);
}
//3. 删除一个无头单链表的非尾节点(不能遍历链表)
void DeleteNotTail(pNode pos)
{
if (pos == NULL)
return;
pNode pcur = pos->_next;
pos->_data = pcur->_data;
pos->_next = pcur->_next;
free(pcur);
pcur = NULL;
}
//4. 在无头单链表的一个非头节点前插入一个节点
void PushInNotHeadFront(pNode pos,int data)
{
pNode pNewNode = (pNode)malloc(sizeof(node_t));
pNewNode->_data = data;
pNewNode->_next = NULL;
pNode pNext = pos->_next;
pNewNode->_next = pNext;
pos->_next = pNewNode;
int temp = pos->_data;
pos->_data = pNewNode->_data;
pNewNode->_data = temp;
}
//5. 单链表实现约瑟夫环(JosephCircle)
void JosephCircle(int n)
{
if (head == NULL)
return;
pNode pcur = head;
while (pcur->_next)
{
pcur = pcur->_next;
}
pcur->_next = head;
int count = 1;
pcur = head;
while (pcur)
{
if (count == n)
{
pNode pDel = pcur;
printf("%d ", pDel->_data);
if (pDel->_next!=pDel)
{
DeleteNotTail(pDel);
count = 1;
}
else
{
free(pDel);
pDel = NULL;
pcur = NULL;
}
}
++count;
if (pcur)
pcur = pcur->_next;
}
}
//6. 逆置 / 反转单链表
void ReverseLinkList()
{
pNode pPre = NULL;
pNode pcur = head;
pNode pNext = head->_next;
while (pcur->_next)
{
pcur->_next = pPre;
pPre = pcur;
pcur = pNext;
pNext = pNext->_next;
}
pcur->_next = pPre;
head = pcur;
}
//7. 单链表排序(冒泡排序&快速排序)
void BubbleSort(std::vector<pNode> v)
{
int size = v.size();
for (int j = 0; j < size - 1; j++)
for (int i = 0; i < size - j - 1;i++)
if (v[i]->_data > v[i+1]->_data)
{
int tmp = v[i]->_data;
v[i]->_data = v[i+1]->_data;
v[i+1]->_data = tmp;
}
}
void Swap(std::vector<pNode> v, int left, int right)
{
int tmp = v[left]->_data;
v[left]->_data = v[right]->_data;
v[right]->_data = tmp;
}
int adjust(std::vector<pNode> v, int left, int right)
{
int key = left;
while (left < right)
{
while (left<right&&v[right]->_data >= v[key]->_data)
right--;
while (left<right&&v[left]->_data <= v[key]->_data)
left++;
if (left<right)
Swap(v, left, right);
}
Swap(v, key, left);
return left;
}
void QuickSort(std::vector<pNode> v,int left, int right)
{
if (left < right)
{
int n = adjust(v, left, right);
QuickSort(v, left, n - 1);
QuickSort(v, n + 1, right);
}
}
void SortLinkList()
{
if (head == NULL)
return;
pNode pcur = head;
std::vector<pNode> v;
while (pcur)
{
v.push_back(pcur);
pcur = pcur->_next;
}
int size = v.size();
//BubbleSort(v);
QuickSort(v,0,size-1);
head = v[0];
for (int i = 0; i < size - 1; i++)
{
v[i]->_next = v[i + 1];
}
}
//8. 合并两个有序链表, //合并后依然有序
pNode MerageLinklist(pNode h1, pNode h2)
{
if (h1 == NULL)
return h2;
if (h2 == NULL)
return h1;
pNode pNewHead = NULL;
if (h1->_data < h2->_data)
{
pNewHead = h1;
pNewHead->_next = MerageLinklist(h1->_next, h2);
}
else
{
pNewHead = h2;
pNewHead->_next = MerageLinklist(h1, h2->_next);
}
return pNewHead;
}
//9. 查找单链表的中间节点,要求只能遍历一次链表
pNode MidOfList()
{
if (head == NULL)
return NULL;
pNode slow = head;
pNode fast = head;
while (fast->_next)
{
slow = slow->_next;
fast = fast->_next->_next;
}
return slow;
}
//10. 查找单链表的倒数第k个节点,要求只能遍历一次链表
pNode LastKNode(int k)
{
if (head == NULL)
return NULL;
pNode first = head;
pNode second = head;
while (k--)
{
first = first->_next;
}
while (first)
{
first = first->_next;
second = second->_next;
}
return second;
}
//11. 删除链表的倒数第K个结点
void DeleteLastKNode(int k)
{
pNode pDel = LastKNode(k);
if (pDel == NULL)
return;
if (pDel->_next)
{
pDel->_data = pDel->_next->_data;
pDel->_next = pDel->_next->_next;
free(pDel->_next);
pDel->_next = NULL;
}
else
{
PopBack();
}
}
//12. 判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复
//杂度&空间复杂度。
pNode ListIsCircle()
{
if (head == NULL)
return NULL;
pNode fast = head->_next;
pNode slow = head;
while (fast->_next)
{
if (fast == slow)
return slow;
fast = fast->_next->_next;
slow = slow->_next;
}
return NULL;
}
int CircleLength()
{
pNode meet = ListIsCircle();
pNode pNext = meet->_next;
int count = 1;
while (pNext != meet)
{
count++;
pNext = pNext->_next;
}
return count;
}
//13. 判断两个链表是否相交,若相交,求交点。(假设链表不带环)
pNode JudgeCross(pNode h1, pNode h2)
{
if (h1 == NULL&&h2 == NULL)
return NULL;
int count1 = 0;
int count2 = 0;
pNode pcur1 = h1;
pNode pcur2 = h2;
while (pcur1)
{
count1++;
pcur1 = pcur1->_next;
}
while (pcur2)
{
count2++;
pcur2 = pcur2->_next;
}
pcur1 = h1;
pcur2 = h2;
int diff = 0;
if (count1 > count2)
{
diff = count1 - count2;
while (diff--)
pcur1 = pcur1->_next;
}
else
{
diff = count2 - count1;
while (diff--)
pcur2 = pcur2->_next;
}
while (pcur1&&pcur2)
{
if (pcur1 == pcur2)
return pcur1;
pcur1 = pcur1->_next;
pcur2 = pcur2->_next;
}
return NULL;
}
//14. 判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
pNode ListIsCircle1(pNode head)
{
if (head == NULL)
return NULL;
pNode fast = head->_next;
pNode slow = head;
while (fast->_next)
{
if (fast == slow)
return slow;
fast = fast->_next->_next;
slow = slow->_next;
}
return NULL;
}
pNode JudgeCrossPlus(pNode h1, pNode h2)
{
pNode meet1 = ListIsCircle1(h1);
pNode meet2 = ListIsCircle1(h2);
if (h1 == NULL || h2 == NULL)
return NULL;
if (meet1 == NULL&&meet2 == NULL)
{
return JudgeCross(h1, h2);
}
else if (meet1!=NULL&&meet2!=NULL)
{
while (meet2->_next != meet2)
{
if (meet2 == meet1)
return meet1;
meet2 = meet2->_next;
}
if (meet1 == meet2)
{
return meet1;
}
else
{
return NULL;
}
}
else
{
return NULL;
}
}
//15. 复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一
//个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,
//返回复制后的新链表。
typedef struct ComplexNode
{
struct ComplexNode * _next;
struct ComplexNode* _random;
int _data;
}CNode;
typedef CNode* PNode;
PNode CHead = NULL;
void CPushBack(int data)
{
PNode pNewNode = (PNode)malloc(sizeof(CNode));
pNewNode->_data = data;
pNewNode->_next = NULL;
pNewNode->_random = NULL;
if (CHead == NULL)
CHead = pNewNode;
else
{
PNode pcur = CHead;
while (pcur->_next)
{
pcur = pcur->_next;
}
pcur->_next = pNewNode;
}
}
void Display2(PNode head)
{
if (head == NULL)
return;
PNode pcur = head;
while (pcur)
{
printf("%d ", pcur->_data);
pcur = pcur->_next;
}
printf("\n");
}
void Clone()
{
PNode pcur = CHead;
while (pcur)
{
PNode pNewNode = (PNode)malloc(sizeof(CNode));
pNewNode->_data = pcur->_data;
pNewNode->_next = NULL;
pNewNode->_random = NULL;
pNewNode->_next = pcur->_next;
pcur->_next = pNewNode;
pcur = pNewNode->_next;
}
Display2(CHead);
}
void Adjust()
{
PNode pcur = CHead;
while (pcur->_next)
{
if (pcur->_random)
pcur->_next->_random = pcur->_random->_next;
pcur = pcur->_next;
}
}
PNode Dismantle()
{
PNode node = CHead;
PNode cloneHead = NULL;
PNode cloneNode = NULL;
if (node)
{
cloneHead = cloneNode = node->_next;
node->_next = cloneNode->_next;
node = node->_next;
}
while (node)
{
cloneNode->_next = node->_next;
cloneNode = cloneNode->_next;
node->_next = cloneNode->_next;
node = node->_next;
}
return cloneHead;
}
PNode CloneComplexList()
{
Clone();
Adjust();
return Dismantle();
}
//16. 求两个已排序单链表中相同的数据。void UnionSet(Node* l1, Node* l2);
void UnionSet(pNode h1, pNode h2)
{
pNode pcur1 = h1;
pNode pcur2 = h2;
if (pcur1 == NULL&&pcur2 == NULL)
return;
while (pcur1&&pcur2)
{
if (pcur1->_data == pcur2->_data)
{
printf("%d ", pcur1->_data);
pcur1 = pcur1->_next;
pcur2 = pcur2->_next;
}
else if (pcur1->_data > pcur2->_data)
{
pcur2 = pcur2->_next;
}
else
pcur1 = pcur1->_next;
}
printf("\n");
}
void Test1()
{
PushBack(1);
PushBack(2);
PushBack(3);
PushBack(4);
PushBack(5);
Display();
PopBack();
Display();
PopBack();
Display();
PopBack();
Display();
}
void Test2()
{
PushFront(1);
PushFront(2);
PushFront(3);
PushFront(4);
PushFront(5);
Display();
PopFront();
Display();
PopFront();
Display();
PopFront();
Display();
}
void Test3()
{
PushBack(1);
PushBack(2);
PushBack(3);
PushBack(4);
PushBack(5);
Display();
DisplayReverse(head);
DeleteNotTail(head->_next->_next);
Display();
}
void Test4()
{
PushBack(1);
PushBack(3);
PushBack(4);
PushBack(5);
Display();
PushInNotHeadFront(head->_next, 2);
Display();
}
void Test5()
{
PushBack(1);
PushBack(2);
PushBack(3);
PushBack(4);
PushBack(5);
Display();
//JosephCircle(3);
ReverseLinkList();
Display();
}
void Test6()
{
PushBack(2);
PushBack(6);
PushBack(1);
PushBack(7);
PushBack(3);
PushBack(4);
Display();
SortLinkList();
Display();
}
void PushBack1(pNode *head, int data)
{
pNode pNewNode = (pNode)malloc(sizeof(node_t));
pNewNode->_data = data;
pNewNode->_next = NULL;
if (*head == NULL)
*head = pNewNode;
else
{
pNode pcur = *head;
while (pcur->_next)
{
pcur = pcur->_next;
}
pcur->_next = pNewNode;
}
}
void Display1(pNode head)
{
if (head == NULL)
return;
pNode pcur = head;
while (pcur)
{
printf("%d ", pcur->_data);
pcur = pcur->_next;
}
printf("\n");
}
void Test7()
{
PushBack1(&head, 0);
PushBack1(&head, 2);
PushBack1(&head, 4);
PushBack1(&head, 6);
PushBack1(&head, 8);
Display1(head);
PushBack1(&head1, 1);
PushBack1(&head1, 3);
PushBack1(&head1, 5);
PushBack1(&head1, 7);
PushBack1(&head1, 9);
Display1(head1);
pNode newhead = MerageLinklist(head, head1);
Display1(newhead);
}
void Test8()
{
PushBack(1);
PushBack(2);
PushBack(3);
PushBack(4);
PushBack(5);
pNode pcur = head;
while (pcur->_next)
pcur = pcur->_next;
pcur->_next = head->_next->_next;
/*Display();*/
/*pNode ret = LastKNode(2);
printf("Last k Node%d\n", ret->_data);
DeleteLastKNode(1);
Display();*/
if (ListIsCircle())
{
printf("List is a circle\n");
printf("entry point%d\n", ListIsCircle()->_data);
printf("circle length:%d\n", CircleLength());
}
else
printf("List is not a circle\n");
/*pNode ret = MidOfList();
if (ret != NULL)
printf("mide node %d\n", ret->_data);
else
printf("NULL");*/
}
void Test9()
{
PushBack1(&head, 0);
PushBack1(&head, 2);
PushBack1(&head, 4);
PushBack1(&head, 6);
PushBack1(&head, 8);
PushBack1(&head, 10);
PushBack1(&head, 12);
Display1(head);
PushBack1(&head1, 1);
PushBack1(&head1, 3);
Display1(head1);
pNode pcur1 = head;
pNode pcur2 = head1;
while (pcur1->_next)
{
pcur1 = pcur1->_next;
}
pcur1->_next = head->_next->_next->_next;
while (pcur2->_next)
{
pcur2 = pcur2->_next;
}
pcur2->_next = head->_next->_next->_next;
pNode ret = JudgeCrossPlus(head, head1);
if (ret == NULL)
printf("not cross\n");
else
printf("cross\n");
printf("meet:%d\n", ret->_data);
}
void Test10()
{
CPushBack(1);
CPushBack(2);
CPushBack(3);
CPushBack(4);
CPushBack(5);
CHead->_next->_next->_next->_random = CHead->_next;
CHead->_next->_next->_random = CHead;
Display2(CHead);
PNode ret = CloneComplexList();
Display2(ret);
}
void Test11()
{
PushBack1(&head, 1);
PushBack1(&head, 3);
PushBack1(&head, 5);
PushBack1(&head, 7);
PushBack1(&head, 9);
Display1(head);
PushBack1(&head1, 0);
PushBack1(&head1, 1);
PushBack1(&head1, 4);
PushBack1(&head1, 5);
PushBack1(&head1, 6);
PushBack1(&head1, 7);
PushBack1(&head1, 9);
Display1(head1);
UnionSet(head,head1);
}
void main()
{
//Test1();
//Test2();
//Test3();
//Test4();
//Test5();
//Test6();
//Test7();
//Test8();
//Test9();
//Test10();
Test11();
}