目录
顺序表使用数组存储线形的元素,其特点是可以随机存取,但是,因为逻辑上相邻的元素物理上也相邻,所以插入删除需要移动元素.
链表使用指针链表示线形表元素的逻辑关系,插入和删除只需修改指针,不能随机存取.
单向链表增加删除节点简单。 遍历时候不会死循环;
链表中数据元素之间的逻辑关系靠的是节点之间的指针,当需要在链表中某处插入或删除节点时,只需改变相应节点的指针指向即可,无需大量移动元素,因此链表中插入、删除或移动数据所耗费的时间复杂度为 O(1)
;
而顺序表中,插入、删除和移动数据可能会牵涉到大量元素的整体移动,因此时间复杂度至少为 O(n)
;
链表存储数据一次只开辟存储一个节点的物理空间,如果后期不够还可以再申请。
- typedef int SLTDataType;
- typedef struct SLlistNode
- {
- SLTDataType data;
- struct SListNode* next;
- }SLTNode;
- SLTNode* BuySLTNode(SLTDataType x)
- {
- SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
- if (newnode == NULL)
- {
- perror("malloc fail");
- exit(-1);
- }
- newnode->data = x;
- newnode->next = NULL;
- return newnode;
- }
malloc函数开辟一个大小为sizeof(SLTNode)字节即一个结构体大小的空间,原本malloc返回值是void类型的指针,但是代码里面的(SLTNode*)将malloc的返回值强制类型转换为SLTNode类型,这样方便了后面数据的存储;
-
- void SLTPrint(SLTNode* phead)
- {
- SLTNode* cur = phead;
- while (cur)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }
调用SLTPrint()函数使,用*phead接收传进来的参数
- void SLTPushBack(SLTNode** phead,SLTDataType x)
- {
- SLTNode* newnode = BuySLTNode(x);
- if (*phead == NULL)
- {
- *phead = newnode;
- }
- else
- {
- SLTNode* ptail = *phead;
- while (ptail->next) //找尾
- {
- ptail = ptail->next;
- }
- ptail->next = newnode;
- }
- }
图解:
首先用ptail记住链表头部的位置,再ptail=ptail->next寻找最后一个节点
- void SLTPopBack(SLTNode** phead)
- {
- assert(*phead);
- //只有一个指针
- if ((*phead)->next==NULL)
- {
- free(*phead);
- *phead = NULL;
- }
- else
- {
- SLTNode* pre = NULL; //记录倒数第二个指针,
- SLTNode* ptail = *phead;
- while (ptail->next)
- {
- pre = ptail;
- ptail = ptail->next;
- }
- free(ptail);
- pre->next = NULL; //将被释放的那个指针置空,避免出现野指针
-
- }
- }
assert(*phead)实现对*phead判空;这里解释一下为什么传参要用双指针,因为改变的是指针,而不是指针的值;
例如:
- //单指针传参交换指针指向的值
- void Swap1(int *p1,int *p2)
- {
- int tmp= *p1; //这里p1解引用之后就是p1指针指向的值
- *P1 = *p2;
- *p2= tmp;
- }
-
- //双指针传参交换指针
- void Swap2(int ** pp1,int **pp2)
- {
- int *tmp=*pp1;
- *pp1 = *pp2;
- *pp2 = tmp;
- }
-
- int main()
- {
- int a=0,b=1;
- Swap1(&a,&b);
-
- int *ptr1 = &a,ptr2 = &b;
- Swap2(&ptr1,&ptr2);
- }
Swap2(&ptr1,&ptr2)通过交换a、b的地址来交换值,而Swap1通过改变指针指向的值来交换值;
总结:1、改变int,传递int *给形参,*形参进行交换改变
2、改变int*,传递int**给形参,*形参进行交换改变
- void SLTPushFront(SLTNode** phead, SLTDataType x)
- {
- SLTNode* newnode = BuySLTNode(x);
- newnode->next = *phead; //
- *phead = newnode; //换头
- }
先将newnode->next指向phead(头节点),再phead=newnode;
- void SLTPopFront(SLTNode** phead)
- {
- assert(*phead);
- SLTNode* newnode = NULL;
- newnode = (*phead)->next; //存储第二个指针
- free(*phead); //释放第一个指针空间
- *phead = newnode; //换头
- }
- SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
- {
- SLTNode* cur = phead;
- while (cur)
- {
- if (cur->data == x)
- {
- return cur;
- }
- cur = cur->next;
- }
- return NULL;
- }
- void SLTInsertAfter(SLTNode** phead, SLTNode* pos, SLTDataType x)
- {
- assert(pos);
- SLTNode* cur = *phead;
- while (cur != pos)
- {
- cur = cur->next;
- }
- SLTNode* newnode = BuySLTNode(x);
- newnode->next = cur->next;
- cur->next = newnode;
-
- }
- void SLTInsert(SLTNode**phead,SLTNode* pos, SLTDataType x)
- {
- assert(pos);
- if (*phead == pos)
- {
- SLTPushFront(phead,x); //头插
- }
- else
- {
- SLTNode* pre = *phead;
- while (pre->next != pos)
- {
- pre = pre->next;
- }
- SLTNode* newnode = BuySLTNode(x);
- pre->next = newnode;
- newnode->next = pos;
- }
- }
- void SLTEraseAfter(SLTNode* pos)
- {
- assert(pos);
- if (pos->next = NULL)
- {
- return;
- }
- else
- {
- SLTNode* next = pos->next;
- pos->next = next->next;
- free(next);
- }
-
- }
图解:
-
- void SLTErase(SLTNode** phead, SLTNode* pos)
- {
- assert(pos);
- assert(*phead);
-
- if (*phead == pos)
- {
- SLTPopFront(phead); //这里不用*phead,因为传过去的是**phead;解引用的时候改变的是*phead;
- }
- else
- {
- SLTNode* pre = *phead;
- while (pre->next != pos)
- {
- pre = pre->next;
- }
- pre->next = pos->next;
- free(pos);
- }
-
- }
- void SLTDestroy(SLTNode** phead)
- {
- SLTNode* cur = *phead;
- while (cur)
- {
- SLTNode* next = cur->next;
- free(cur);
- cur = next;
- }
- *phead = NULL;
- }
我用SList.h存放函数的声明和一些头文件:
- #pragma once
- #include
- #include
- #include
-
- typedef int SLTDataType;
- typedef struct SLlistNode
- {
- SLTDataType data;
- struct SListNode* next;
- }SLTNode;
-
- SLTNode* BuySLTNode(SLTDataType x);
- SLTNode* CreateSList(int n);
- void SLTPrint(SLTNode* phead);
-
- void SLTPushBack(SLTNode** phead, SLTDataType x);
- void SLTPopBack(SLTNode** pphead);
- void SLTPushFront(SLTNode** phead, SLTDataType x);
- void SLTPopFront(SLTNode** phead);
-
- SLTNode* SLTFind(SLTNode* phead, SLTDataType x);// 查找链表中的元素
- void SLTInsertAfter(SLTNode**phead,SLTNode* pos,SLTDataType x);//在pos位置之后插入x
- void SLTInsert(SLTNode** phead, SLTNode* pos, SLTDataType x);//在pos位置前面插入x
-
- void SLTEraseAfter(SLTNode* pos);//删除pos后面的一个元素
-
- void SLTErase(SLTNode** phead, SLTNode* pos);//删除pos位置的元素
- void SLTDestroy(SLTNode** phead);
用SList.c定义函数:
- #define _CRT_SECURE_NO_WARNI
- #include"SList.h"
-
- SLTNode* BuySLTNode(SLTDataType x)
- {
- SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
- if (newnode == NULL)
- {
- perror("malloc fail");
- exit(-1);
- }
- newnode->data = x;
- newnode->next = NULL;
- return newnode;
- }
- //SLTNode* CreateSList(int n)
- //{
- // SLTNode* phead = NULL;
- // SLTNode* ptail = NULL;
- // int x;
- // for (int i = 0; i < n; i++)
- // {
- // SLTNode* newnode = BuySLTNode(i);
- // if (phead == NULL)
- // {
- // ptail = phead = newnode;
- // }
- // else
- // {
- // ptail->next = newnode;
- // ptail = newnode;
- // }
- // }
- // return phead;
- //}
-
- void SLTPrint(SLTNode* phead)
- {
- SLTNode* cur = phead;
- while (cur)
- {
- printf("%d->", cur->data);
- cur = cur->next;
- }
- printf("NULL\n");
- }
-
- void SLTPushBack(SLTNode** phead,SLTDataType x)
- {
- SLTNode* newnode = BuySLTNode(x);
- if (*phead == NULL)
- {
- *phead = newnode;
- }
- else
- {
- SLTNode* ptail = *phead;
- while (ptail->next) //找尾
- {
- ptail = ptail->next;
- }
- ptail->next = newnode;
- }
- }
- void SLTPopBack(SLTNode** phead)
- {
- assert(*phead);
- //只有一个指针
- if ((*phead)->next==NULL)
- {
- free(*phead);
- *phead = NULL;
- }
- else
- {
- SLTNode* pre = NULL; //记录倒数第二个指针,
- SLTNode* ptail = *phead;
- while (ptail->next)
- {
- pre = ptail;
- ptail = ptail->next;
- }
- free(ptail);
- pre->next = NULL; //将被释放的那个指针置空,避免出现野指针
-
- }
- }
-
- void SLTPushFront(SLTNode** phead, SLTDataType x)
- {
- SLTNode* newnode = BuySLTNode(x);
- newnode->next = *phead; //
- *phead = newnode; //换头
- }
-
-
- void SLTPopFront(SLTNode** phead)
- {
- assert(*phead);
- SLTNode* newnode = NULL;
- newnode = (*phead)->next; //存储第二个指针
- free(*phead); //释放第一个指针空间
- *phead = newnode; //换头
- }
-
- SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
- {
- SLTNode* cur = phead;
- while (cur)
- {
- if (cur->data == x)
- {
- return cur;
- }
- cur = cur->next;
- }
- return NULL;
- }
-
- void SLTInsertAfter(SLTNode** phead, SLTNode* pos, SLTDataType x)
- {
- assert(pos);
- SLTNode* cur = *phead;
- while (cur != pos)
- {
- cur = cur->next;
- }
- SLTNode* newnode = BuySLTNode(x);
- newnode->next = cur->next;
- cur->next = newnode;
-
- }
-
- void SLTInsert(SLTNode**phead,SLTNode* pos, SLTDataType x)
- {
- assert(pos);
- if (*phead == pos)
- {
- SLTPushFront(phead,x); //头插
- }
- else
- {
- SLTNode* pre = *phead;
- while (pre->next != pos)
- {
- pre = pre->next;
- }
- SLTNode* newnode = BuySLTNode(x);
- pre->next = newnode;
- newnode->next = pos;
- }
- }
-
- void SLTEraseAfter(SLTNode* pos)
- {
- assert(pos);
- if (pos->next = NULL)
- {
- return;
- }
- else
- {
- SLTNode* next = pos->next;
- pos->next = next->next;
- free(next);
- }
-
- }
-
- void SLTErase(SLTNode** phead, SLTNode* pos)
- {
- assert(pos);
- assert(*phead);
-
- if (*phead == pos)
- {
- SLTPopFront(phead); //这里不用*phead,因为传过去的是**phead;解引用的时候改变的是*phead;
- }
- else
- {
- SLTNode* pre = *phead;
- while (pre->next != pos)
- {
- pre = pre->next;
- }
- pre->next = pos->next;
- free(pos);
- }
-
- }
-
- void SLTDestroy(SLTNode** phead)
- {
- SLTNode* cur = *phead;
- while (cur)
- {
- SLTNode* next = cur->next;
- free(cur);
- cur = next;
- }
- *phead = NULL;
- }
用test.c写主函数和函数调用:
- #define _CRT_SECURE_NO_WARNINGS
- #include"SList.h"
- //void test1()
- //{
- // SLTNode* plist = NULL;
- // plist=CreateSList(3);
- // SLTPrint(plist);
- //}
- //
- //void testSLTNode2()
- //{
- // SLTNode* plist = NULL;
- // SLTPushBack(&plist, 1);
- // SLTPushBack(&plist, 2);
- // SLTPushBack(&plist, 3);
- // SLTPushBack(&plist, 4);
- //
- // SLTPopBack(&plist);
- //
- // SLTPrint(plist);
- //}
- //
- //void testSTLNode3()
- //{
- // SLTNode* plist = NULL;
- // SLTPushFront(&plist,1);
- // SLTPushFront(&plist,2);
- // SLTPushFront(&plist,3);
- // SLTPushFront(&plist,4);
- // SLTPushFront(&plist,5);
- //
- // SLTPrint(plist);
- //
- // SLTPopFront(&plist);
- // SLTPopFront(&plist);
- //
- // printf("\n");
- // SLTPrint(plist);
- //}
- //void testSLTNode4()
- //{
- // SLTNode* plist = NULL;
- // SLTPushFront(&plist, 2);
- // SLTPushFront(&plist, 3);
- // SLTPushFront(&plist, 5);
- //
- // SLTNode *p = SLTFind(plist, 5);
- // SLTInsertAfter(p, 99);
- //
- // SLTPrint(plist);
- //}
-
- //void testSLTNode5()
- //{
- // SLTNode* plist = NULL;
- // SLTPushBack(&plist, 1);
- // SLTPushBack(&plist, 2);
- // SLTPushBack(&plist, 5);
- //
- // SLTNode* p = SLTFind(plist, 1);
- // SLTInsertAfter(&plist,p , 6);
- //
- // SLTPrint(plist);
- //}
-
- void testSLTNode6()
- {
- SLTNode* plist = NULL;
- SLTPushBack(&plist, 1);
- SLTPushBack(&plist, 2);
- SLTPushBack(&plist, 3);
- SLTPushFront(&plist, 4);
- SLTPushFront(&plist, 5);
- SLTPushFront(&plist, 6);
-
- SLTNode* p = SLTFind(plist, 4);
- SLTInsert(&plist,p, 100);
-
- SLTPrint(plist);
-
- p = SLTFind(plist, 5);
- SLTInsertAfter(&plist,p, 200);
-
- SLTPrint(plist);
-
- p = SLTFind(plist, 100);
- SLTErase(&plist, p);
- SLTPrint(plist);
- p = NULL;
-
- SLTDestroy(&plist);
- SLTPrint(plist);
- }
-
- int main()
- {
- //test1();
- //testSLTNode2();
- //testSTLNode3();
- //testSLTNode4();
- //testSLTNode5();
- testSLTNode6();
- return 0;
- }
运行结果: