认识什么是链表和数组,他们有什么区别?
数组:内存是连续的。
优缺点:
优点:
1.下标访问(随机访问)时间复杂度是O(1)
2.末尾位置增加删除元素时间复杂度是O(1)
3.访问元素前后相邻位置的元素非常方便
缺点:
1.非末尾位置增加删除元素需要进行大量的数据移动O(n)
2.搜索的时间复杂度:
无序数组-线性搜索O(n)
有序数组-二分搜索O(logn)
3.数组扩容消耗比较大,少了需要再扩容,多了浪费资源!
单链表:每一个节点都是在堆内存上独立new出来的,节点内存不连续。
优缺点:
优点:
1.内存利用率高,不需要大块连续内存
2.插入和删除节点不需要移动其它节点,时间复杂度O(1)
3.不需要专门进行扩容操作
缺点:
1.内存占用量大,每一个节点多出存放地址的空间
2.节点内存不连续,无法进行内存随机访问
3.链表搜索效率不高,只能从头节点开始逐节点遍历
全部源代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef int SLTDataType;
//创建链表
typedef struct SListNode
{
SLTDataType data; //数据域
struct SListNode* next;
}SLTNode;
//遍历链表,打印数据
void SListPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
//清空链表
void SListClear(SLTNode** pphead)
{
SLTNode* cur = *pphead;
SLTNode* nextNode = NULL;
while (cur != NULL)
{
nextNode = cur->next;
free(cur);
cur = nextNode;
}
*pphead = NULL;
}
//创建链表节点
SLTNode* CreateSListNode(SLTDataType x)
{
SLTNode* NewNode = (SLTNode*)malloc(sizeof(SLTNode)); //用malloc动态开辟一个节点空间大小
NewNode->data = x; //新节点的data存放数据
NewNode->next = NULL; //新节点的next指向空指针
return NewNode;
}
//尾部插入节点
void SListPushBack(SLTNode** pphead, SLTDataType x) //传链表plist的地址和数据
{
SLTNode* NewNode = CreateSListNode(x); //创建新节点
//当链表为空
if (*pphead == NULL)
{
*pphead = NewNode; //把头指针指向新的节点
}
else
{
SLTNode* tail = *pphead; //先把头指针指向尾节点,通过循环把尾节点放到最后面
while (tail->next != NULL) //如果尾节点的next不等于空指针就把尾节点往后移
{
tail = tail->next; //当尾节点移到最后一个位置时,跳出循环
}
tail->next = NewNode; //最后把新节点赋给尾节点
}
}
//尾部删除节点
void SListPopBack(SLTNode** pphead)
{
//链表为空
if (*pphead == NULL) //如果尾节点为空,什么也不返回
{
return;
}
//只有一个节点
else if ((*pphead)->next == NULL) //只有一个节点的时候,删除了就会出现野指针
{
free(*pphead);
*pphead = NULL; //需要把头指针置为空,防止出现野指针
}
//有多个节点
else
{
SLTNode* prev = NULL; //指向尾节点的前一个节点
SLTNode* tail = *pphead; //指向尾节点
while (tail->next != NULL) //如果尾节点的next不等于空指针就把尾节点往后移
{
prev = tail; //把尾指针复制到前一个指针(头指针)
tail = tail->next; //尾指针指向下一个节点
}
free(tail); //当尾指针指向NULL时
prev->next = NULL; //此时尾节点的前一个节点就移动到最后,要把它置为空指针,防止出现野指针
}
}
//头部插入节点
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
SLTNode* NewNode = CreateSListNode(x); //创建新的节点
NewNode->next = *pphead; //把头指针指向新节点的next
*pphead = NewNode; //把新节点放到头结点位置
}
//头部删除节点
void SListPopFront(SLTNode** pphead)
{
if (*pphead == NULL) //空链表的时候,什么也不返回
{
return;
}
SLTNode* nextnode = (*pphead)->next; //新节点指向头结点的next
free(*pphead); //
*pphead = nextnode; //
}
//查找值为x的节点并返回节点的指针
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
SLTNode* cur = phead;
while (cur != NULL)
{
if (cur->data == x)
{
return cur; //找到返回该结点指针
}
cur = cur->next;
}
//找不到返回NULL指针
return NULL;
}
//在pos指针前一个插入一个节点
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
//pos在第一个节点,相当与头插
if (*pphead == pos)
SListPushFront(pphead, x);
else
{
SLTNode* NewNode = CreateSListNode(x);
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = NewNode;
NewNode->next = pos;
}
}
//删除pos指针指向的结点
void SListErese(SLTNode** pphead, SLTNode* pos)
{
if (*pphead == pos)
{
SListPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
}
}
//主函数,程序从这里进入
int main()
{
SLTNode* plist = NULL;
//尾插
printf("\n尾部插入5个数据:15 16 17 18 19\n");
printf("链表:");
SListPushBack(&plist, 15);
SListPushBack(&plist, 16);
SListPushBack(&plist, 17);
SListPushBack(&plist, 18);
SListPushBack(&plist, 19);
SListPrint(plist); //打印链表
//尾删
printf("\n尾部删除2个数据:18 19\n");
SListPopBack(&plist);
SListPopBack(&plist);
printf("链表:");
SListPrint(plist);
//头插
printf("\n头部插入3个数据: 77 29 64\n");
SListPushFront(&plist, 64);
SListPushFront(&plist, 29);
SListPushFront(&plist, 77);
printf("链表:");
SListPrint(plist);
//头删
printf("\n头部删除1个数据:77\n");
SListPopFront(&plist);
printf("链表:");
SListPrint(plist);
return 0;
}
创建链表
typedef int SLTDataType;
//创建链表
typedef struct SListNode
{
SLTDataType data; //数据域
struct SListNode* next; //指针域
}SLTNode;
创建链表的节点
//创建链表节点
SLTNode* CreateSListNode(SLTDataType x)
{
SLTNode* NewNode = (SLTNode*)malloc(sizeof(SLTNode)); //用malloc动态开辟一个节点空间大小
NewNode->data = x; //新节点的data存放数据
NewNode->next = NULL; //新节点的next指向空指针
return NewNode;
}
清空链表的数据
//清空链表
void SListClear(SLTNode** pphead)
{
SLTNode* cur = *pphead;
SLTNode* nextNode = NULL;
while (cur != NULL)
{
nextNode = cur->next;
free(cur); //清空一个,就把该节点的空间释放掉,直到全部节点都被删除完
cur = nextNode;
}
*pphead = NULL; //防止出现野指针
}
链表尾部插入节点
//尾部插入节点
void SListPushBack(SLTNode** pphead, SLTDataType x) //传链表plist的地址和数据
{
SLTNode* NewNode = CreateSListNode(x); //创建新节点
//当链表为空
if (*pphead == NULL)
{
*pphead = NewNode; //把头指针指向新的节点
}
else
{
SLTNode* tail = *pphead; //先把头指针指向尾节点,通过循环把尾节点放到最后面
while (tail->next != NULL) //如果尾节点的next不等于空指针就把尾节点往后移
{
tail = tail->next; //当尾节点移到最后一个位置时,跳出循环
}
tail->next = NewNode; //最后把新节点赋给尾节点
}
}
链表尾部删除节点
//尾部删除节点
void SListPopBack(SLTNode** pphead)
{
//链表为空
if (*pphead == NULL) //如果尾节点为空,什么也不返回
{
return;
}
//只有一个节点
else if ((*pphead)->next == NULL) //只有一个节点的时候,删除了就会出现野指针
{
free(*pphead);
*pphead = NULL; //需要把头指针置为空,防止出现野指针
}
//有多个节点
else
{
SLTNode* prev = NULL; //指向尾节点的前一个节点
SLTNode* tail = *pphead; //指向尾节点
while (tail->next != NULL) //如果尾节点的next不等于空指针就把尾节点往后移
{
prev = tail; //把尾指针复制到前一个指针(头指针)
tail = tail->next; //尾指针指向下一个节点
}
free(tail); //当尾指针指向NULL时
prev->next = NULL; //此时尾节点的前一个节点就移动到最后,要把它置为空指针,防止出现野指针
}
}
链表头部插入节点
//头部插入节点
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
SLTNode* NewNode = CreateSListNode(x); //创建新的节点
NewNode->next = *pphead; //把头指针指向新节点的next
*pphead = NewNode; //把新节点放到头结点位置
}
链表头部删除节点
//头部删除节点
void SListPopFront(SLTNode** pphead)
{
if (*pphead == NULL) //空链表的时候,什么也不返回
{
return;
}
SLTNode* nextnode = (*pphead)->next; //新节点指向头结点的next
free(*pphead);
*pphead = nextnode;
}
查找链表任意位置的节点
//查找值为x的节点并返回节点的指针
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
SLTNode* cur = phead;
while (cur != NULL)
{
if (cur->data == x)
{
return cur; //找到返回该结点指针
}
cur = cur->next;
}
//找不到返回NULL指针
return NULL;
}
在链表的任意位置插入节点
//在pos指针前一个插入一个节点
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
//pos在第一个节点,相当与头插
if (*pphead == pos)
SListPushFront(pphead, x);
else
{
SLTNode* NewNode = CreateSListNode(x);
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = NewNode;
NewNode->next = pos;
}
}
在链表的任意位置删除节点
//删除pos指针指向的结点
void SListErese(SLTNode** pphead, SLTNode* pos)
{
if (*pphead == pos)
{
SListPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
}
}