顺序表和链表的优缺点
顺序表:
优点:顺序表是将数据存储在一段连续的内存中,可以通过下标随机访问,效率高。
缺点:插入和删除数据时效率很低,移动数据时需要表里。增容时需要重新开辟内存,有可能造成浪费。
链表:
优点:链表在程序运行时动态分配内存,插入和删除速度快。
缺点:不支持随机访问,查找时需要遍历链表。
从各自的优缺点根据使用场景选择。频繁插入、删除使用链表。反之,频繁查找选择顺序表。
void Print_TailToHead(ListNode *pList)//从尾到头打印
{
if(!pList)
{
printf("NULL");
return;
}
Print_TailToHead(pList->next);
printf("->%d", pList->data);
}
void Erase_Notail(ListNode *pos)//删除一个无头单链表的非尾节点
{
ListNode *tmp = pos->next;
assert((pos) && (pos->next));
pos->data = tmp->data;
pos->next = tmp->next;
free(tmp);
}
void Insert_Nohead(ListNode *pos, DataType x)//在无头单链表的一个节点前插入一个节点
{
ListNode *tmp = CreatNode(pos->data);
assert(pos);
pos->data = x;
tmp->next = pos->next;
pos->next = tmp;
}
DataType Josephus(ListNode *pList, int k)//单链表实现约瑟夫环
{
ListNode *tmp = pList;
while(tmp->next)
{
tmp = tmp->next;
}
tmp->next = pList;
while(pList->next != pList)
{
int ret = k;
while(--ret)
{
pList = pList->next;
}
tmp = pList->next;
pList->data = tmp->data;
pList->next = tmp->next;
free(tmp);
}
return pList->data;
}
void Severse(ListNode **ppList)//逆置/反转单链表
{
ListNode *Now = NULL;
if((*ppList == NULL)||((*ppList)->next == NULL))
{
return;
}
while((*ppList)->next)
{
ListNode *tmp = (*ppList)->next;
(*ppList)->next = Now;
Now = *ppList;
*ppList = tmp;
}
(*ppList)->next = Now;
}
void Bubble_sort(ListNode *ppList)//单链表排序(冒泡排序&快速排序)
{
ListNode *p1 = ppList;
ListNode *tmp = NULL;
if((ppList == NULL) || (ppList->next == NULL))
{
return;
}
while(p1 != tmp)
{
ListNode *pList2 = ppList->next;//定义在这里为了防止ppList为空
while(pList2 != tmp)
{
if((p1->data)>(pList2->data))
{
DataType ret = p1->data;
p1->data = pList2->data;
pList2->data = ret;
}
p1 = p1->next;
pList2 = pList2->next;
}
tmp = p1;
p1 = ppList;
pList2 = ppList->next;
}
}
ListNode* Combine(ListNode *pList1, ListNode *pList2)//合并两个有序链表,合并后依然有序
{
ListNode *head = NULL;
ListNode *NowList = NULL;
if(pList1 == NULL)
return pList2;
if(pList2 == NULL)
return pList1;
if(pList1->data < pList2->data)
{
head = pList1;
pList1 = pList1->next;
}
else
{
head = pList2;
pList2 = pList2->next;
}
NowList = head;
while((pList1!=NULL) && (pList2!=NULL))
{
if((pList1->data) < (pList2->data))
{
NowList->next = pList1;
pList1 = pList1->next;
NowList = NowList->next;
}
else
{
NowList->next = pList2;
pList2 = pList2->next;
NowList = NowList->next;
}
}
if(pList1 == NULL)
NowList->next = pList2;
else
NowList->next = pList1;
return head;
}
ListNode* Find_MidNode(ListNode *pList)//查找单链表的中间节点,要求只能遍历一次链表
{
ListNode *fast = pList;//这里当然也可以时pList,但返回值有区别,不信可以验证下
ListNode *slow = pList;
assert(pList);
if((pList == NULL) || (pList->next == NULL))
return pList;
while((fast->next != NULL) && (fast->next->next != NULL))
{
fast = fast->next->next;
slow = slow->next;
}
return slow;//当链表个数为偶数时:slow返回中间两个节点的前一个节点,slow->next返回中间节点的后一个节点
}
ListNode* Find_Rec_k_Node(ListNode *pList, int k)//查找单链表的倒数第k个节点,要求只能遍历一次链表
{
ListNode *fast = pList;
ListNode *slow = pList;
assert(pList && k);
while(--k)
{
fast = fast->next;
if(fast == NULL)
return NULL;
}
while(fast->next != NULL)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
关于链表的所有测试用例
#include "List.h"
void test1()//测试PushBack/PopBack
{
ListNode *List = NULL;
PushBack(&List, 1);
PushBack(&List, 2);
PushBack(&List, 3);
PushBack(&List, 4);
PrintList(List);
Print_TailToHead(List);
printf("\n");
PopBack(&List);
PopBack(&List);
PrintList(List);
PopBack(&List);
PopBack(&List);
PrintList(List);
}
void test2()//测试PushFront/PopFront
{
ListNode *List = NULL;
PushFront(&List, 4);
PushFront(&List, 3);
PushFront(&List, 2);
PushFront(&List, 1);
PrintList(List);
PopFront(&List);
PopFront(&List);
PrintList(List);
PopFront(&List);
PopFront(&List);
PrintList(List);
}
void test3()//测试Insert/Erase
{
ListNode *List = NULL;
ListNode *ret = NULL;
PushBack(&List, 1);
PushBack(&List, 2);
PushBack(&List, 3);
PushBack(&List, 4);
PrintList(List);
ret = Find(List, 4);
Insert(&List, ret, 0);
PrintList(List);
ret = Find(List, 4);
Erase(&List, ret);
PrintList(List);
}
void test4()//测试Erase_Notail/Insert_Nohead
{
ListNode *List = NULL;
ListNode *pos = NULL;
PushBack(&List, 1);
PushBack(&List, 2);
PushBack(&List, 3);
PushBack(&List, 4);
PrintList(List);
pos = Find(List, 2);
Erase_Notail(pos);
PrintList(List);
pos = Find(List, 3);
Insert_Nohead(pos, 2);
PrintList(List);
}
void test5()//测试Josephus
{
ListNode *List = NULL;
DataType tmp = 0;
PushBack(&List, 1);
PushBack(&List, 2);
PushBack(&List, 3);
PushBack(&List, 4);
PrintList(List);
tmp = Josephus(List, 3);
printf("%d\n", tmp);
}
void test6()//测试Severse/Bubble_sort
{
ListNode *List = NULL;
PushBack(&List, 1);
PushBack(&List, 2);
PushBack(&List, 3);
PushBack(&List, 4);
PrintList(List);
Severse(&List);
PrintList(List);
Bubble_sort(List);
PrintList(List);
}
void test7()//测试Combine
{
ListNode *List1 = NULL;
ListNode *List2 = NULL;
ListNode *Now = NULL;
PushBack(&List1, 3);
PushBack(&List1, 3);
PushBack(&List1, 6);
PushBack(&List2, 1);
PushBack(&List2, 2);
PushBack(&List2, 2);
PushBack(&List2, 7);
Now = Combine(List1, List2);
PrintList(Now);
}
void test8()//测试Find_MidNode
{
ListNode *List = NULL;
ListNode *ret = NULL;
PushBack(&List, 1);
PushBack(&List, 2);
PushBack(&List, 3);
PushBack(&List, 4);
PushBack(&List, 5);
PushBack(&List, 6);
ret = Find_MidNode(List);
printf("%d\n", ret->data);
}
void test9()//测试Find_Rec_k_Node
{
ListNode *List = NULL;
ListNode *ret = NULL;
PushBack(&List, 1);
PushBack(&List, 2);
PushBack(&List, 3);
PushBack(&List, 4);
PushBack(&List, 5);
PushBack(&List, 6);
ret = Find_Rec_k_Node(List, 3);
printf("%d\n", ret->data);
}
void test10()//测试judge_band/judge_band_length/judge_band
{
ListNode *List = NULL;
ListNode *tmp = NULL;
ListNode *tail = NULL;
PushBack(&List, 1);
PushBack(&List, 2);
PushBack(&List, 3);
PushBack(&List, 4);
PushBack(&List, 5);
PushBack(&List, 6);
tmp = Find(List, 3);
tail = Find(List, 6);
tail->next = tmp;
printf("%p\n", judge_band(List));
printf("%d\n", judge_band_length(List));
printf("%p\n", Find(List, 3));
}
void test11()//测试judge_intersect/judge_junction
{
ListNode *List1 = NULL;
ListNode *List2 = NULL;
ListNode *p1 = NULL;
ListNode *p2 = NULL;
PushBack(&List1, 1);
PushBack(&List1, 2);
PushBack(&List1, 3);
PushBack(&List1, 4);
PushBack(&List1, 5);
PushBack(&List1, 6);
p1 = Find(List1, 3);
PushBack(&List2, 1);
PushBack(&List2, 2);
PushBack(&List2, 3);
PushBack(&List2, 4);
p2 = Find(List2, 4);
p2->next = p1;
printf("%p\n", judge_intersect(List1, List2));
//printf("%p\n", judge_junction(List1, List2));
printf("%p\n", Find(List1, 3));
}
void test12()//测试judge_band_intersect
{
ListNode *List1 = NULL;
ListNode *List2 = NULL;
ListNode *p1 = NULL;
ListNode *p2 = NULL;
PushBack(&List1, 1);
PushBack(&List1, 2);
PushBack(&List1, 3);
PushBack(&List1, 4);
PushBack(&List1, 5);
PushBack(&List1, 6);
p1 = Find(List1, 3);
p2 = Find(List1, 6);
p2->next = p1;
PushBack(&List2, 1);
PushBack(&List2, 2);
PushBack(&List2, 3);
PushBack(&List2, 4);
PushBack(&List2, 5);
PushBack(&List2, 6);
//测试都带环但不相交
//p2 = Find(List2, 6);
//p1 = Find(List2, 3);
//p2->next = p1;
//测试都带环且相交
p2 = Find(List2, 6);
p1 = Find(List1, 5);
p2->next = p1;
printf("%p\n", judge_band_intersect(List1, List2));
printf("%p\n", judge_band(List1));
printf("%p\n", judge_band(List2));
printf("%p\n", Find(List1, 3));
printf("%p\n", Find(List2, 3));
}
void test13()//测试cpye_dif_List
{
ListNode *List = NULL;
ListNode *NewList = NULL;
ListNode *p1 = NULL;
ListNode *p2 = NULL;
ListNode *p3 = NULL;
ListNode *p4 = NULL;
ListNode *p5 = NULL;
PushBack(&List, 1);
PushBack(&List, 2);
PushBack(&List, 3);
PushBack(&List, 4);
PushBack(&List, 5);
p1 = Find(List, 1);
p2 = Find(List, 2);
p3 = Find(List, 3);
p4 = Find(List, 4);
p5 = Find(List, 5);
p1->random = p3;
p2->random = p1;
p3->random = p3;
p4->random = p2;
p5->random = p4;
NewList = cpye_dif_List(List);
PrintList(List);
PrintList(NewList);
}
int main()
{
//test1();
//test2();
//test3();
//test4();
//test5();
//test6();
//test7();
//test8();
//test9();
//test10();
//test11();
//test12();
//test13();
return 0;
}
代码是测试过得,如有不对不完善之处,欢迎留言指正.