1.顺序便与单链表比较
顺序表:顺序表存储是将数据元素放到一块连续的内存储空间,相邻数据元素的存放地址也相邻,有动态存储和静态存储两种存储方式。
优点:(1)可以直接通过下标访问,支持随机访问,查找等效率较高。
(2)数据连续存放,空间利用率高,命中率高。
缺点:(1)当元素个数远小于预先分配的空间大小时,空间浪费比较严重;静态存储时,空间一经创建,大小不能改变,当需要存取的元素个数可能多于顺序表的元素个数时,会出现溢出问题。
(2)插入或删除数据效率较低,顺序表需要遍历移动元素。
链表:链表存储是程序运行过程中动态分配空间,相邻数据元素可任意存放,但所占存储空间分为两部分,一部分存放节点值,另一部分存放便是节点间关系的指针。
优点:(1)插入和删除效率较高,只需要改变指针指向即可。
(2)没有空间限制,只要存储器还有空间,就不会产生溢出问题。
缺点:(1)数据存放不连续,malloc开辟,空间碎片较多。
(2)查找速度较慢,当需要访问某个数据时,需要从第一个节点开始逐个查找。 适用场合:若线性表长度变化不大,且主要操作是查找很少插入删除时,可以采用顺序表;若线性表长度变化较大或者根本不知道多大,且其主要操作是插入删除很少查找时,可以采用链表,这样可以不用考虑存储空间大小问题。
//list.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#pragma once
typedef int DataType;
typedef struct ListNode
{
DataType data;
struct ListNode* next;
}ListNode;
2.从尾到头打印单链表
void PrintTailToHead(ListNode* ppHead)
{
if (ppHead == NULL)
{
return;
}
PrintTailToHead(ppHead->next);
printf("%d ", ppHead->data);
}
3.删除一个无头单链表的非尾节点
void ErasenoTail(ListNode* pos)
{
ListNode* next;
assert(pos&&pos->next);
if (pos == -1)
{
return;
}
next = pos->next;
pos->data = next->data;
pos->next = next->next;
free(next);
}
4.在无头单链表的一个节点前插入一个节点
void InsertnoTail(ListNode* pos,DataType x)
{
assert(pos);
if (pos == -1)
{
return;
}
ListNode* next= BuyNode(pos->data);
next->next = pos->next;
pos->next = next;
pos->data = x;
}
5.单链表实现约瑟夫环
ListNode* Joseph(ListNode* hus, size_t k)
{
ListNode* man,*next;
assert(hus);
man = hus;
while (man->next != man)
{
size_t count = k;
while (--count)
{
man = man->next;
}
next = man->next;
man->data = next->data;
man->next = next->next;
free(next);
}
return man;
}
6.逆置/反转单链表
void Reverse(ListNode** ppHead)
{
if (*ppHead == NULL)
{
return ;
}
else
{
ListNode* n0 = NULL, *n1 = *ppHead, *n2 = n1->next;
while (n1)
{
n1->next = n0;
n0 = n1;
n1 = n2;
if (n2)
{
n2 = n2->next;
}
}
*ppHead = n0;
}
}
7.单链表排序(冒泡排序&快速排序)
void SortList(ListNode* pHead)
{
ListNode* tail = NULL;
if (pHead==NULL&&pHead->next==NULL)
{
return;
}
while (tail!=pHead)
{
int exchange = 0;
ListNode* cur = pHead, *next = cur->next;
while (next != tail)
{
if (cur->data > next->data)
{
exchange = 1;
DataType tmp = cur->data;
cur->data = next->data;
next->data = tmp;
}
cur = cur->next;
next = next->next;
}
if (exchange == 0)
{
break;
}
tail = cur;
}
}
8.合并两个有序链表,合并后依然有序
ListNode* MergeList(ListNode* list1, ListNode* list2)
{
ListNode* list,*tail;
if (list1 == NULL)
return list2;
if (list2 == NULL)
return list1;
if (list1->data < list2->data)
{
list = list1;
list1 = list1->next;
}
else
{
list = list2;
list2 = list->next;
}
tail = list;
while (list1&&list2)
{
if (list1->data < list2->data)
{
tail->next = list1;
list1 = list1->next;
}
else
{
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}
if (list1 != NULL)
{
tail->next = list1;
}
else
{
tail->next = list2;
}
return list;
}
9.查找单链表的中间节点,要求只能遍历一次链表
ListNode* FindMidNode(ListNode* pHead)
{
ListNode* slow = pHead;
ListNode* fast = pHead;
while (fast && fast->next&&fast->next->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
10.查找单链表的倒数第k个节点,要求只能遍历一次链表
ListNode* FindTailkNode(ListNode* pHead, size_t k)
{
ListNode* slow = pHead, *fast = pHead;
while (--k)
{
if (fast == NULL)
{
return NULL;
}
fast = fast->next;
}
while (fast->next)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
//test.c
//Reverse/ErasenoTail/InsertnoTail/PrintTailToHead
void TestList1()
{
ListNode* list = NULL;
PushBack(&list, 0);
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PushBack(&list, 5);
PrintList(list);
PrintTailToHead(list);
Reverse(&list);
PrintList(list);
ErasenoTail(Find(list,2));
PrintList(list);
InsertnoTail(Find(list, 3),30);
InsertnoTail(Find(list, 2),40);
PrintList(list);
}
//Joseph
void TestList2()
{
ListNode* tail;
ListNode* list = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
PushBack(&list, 5);
tail = Find(list, 5);
tail->next = list;
printf("live:%d\n", Joseph(list, 3)->data);
}
//SortList
void TestList3()
{
ListNode* list = NULL;
PushBack(&list, 5);
PushBack(&list, 3);
PushBack(&list, 2);
PushBack(&list, 7);
PushBack(&list, 9);
SortList(list);
PrintList(list);
}
//MergeList
void TestList4()
{
ListNode* list;
ListNode* list1 = NULL;
ListNode* list2= NULL;
PushBack(&list1, 1);
PushBack(&list1, 3);
PushBack(&list1, 5);
PushBack(&list1, 7);
PushBack(&list1, 9);
PushBack(&list2, 0);
PushBack(&list2, 2);
PushBack(&list2, 4);
PushBack(&list2, 6);
PushBack(&list2, 8);
list=MergeList(list1, list2);
PrintList(list);
}
//FindMidNode/FindTailkNode
void TestList5()
{
ListNode* list1=NULL;
PushBack(&list1, 0);
PushBack(&list1, 1);
PushBack(&list1, 3);
PushBack(&list1, 5);
PushBack(&list1, 7);
PushBack(&list1, 9);
SortList(list1);
printf("mid:%d\n", FindMidNode(list1)->data);
printf("tail k:%d\n", FindTailkNode(list1,3)->data);
}
#include test.h
int main()
{
TestList5();
system("pause");
return 0;
}
“`