
SeqList.h
#pragma once #include#include #include #include #include typedef int SLDataType; // 顺序表的动态存储 typedef struct SeqList { SLDataType* array; // 指向动态开辟的数组 size_t size; // 有效数据个数 size_t capicity; // 容量空间的大小 }SeqList; SeqList SL; // 基本增删查改接口 // 顺序表初始化 void SeqListInit(SeqList* psl); // 检查空间,如果满了,进行增容 void CheckCapacity(SeqList* psl); // 顺序表尾插 void SeqListPushBack(SeqList* psl, SLDataType x); // 顺序表尾删 void SeqListPopBack(SeqList* psl); // 顺序表头插 void SeqListPushFront(SeqList* psl, SLDataType x); // 顺序表头删 void SeqListPopFront(SeqList* psl); // 顺序表查找 int SeqListFind(SeqList* psl, SLDataType x); // 顺序表在pos位置插入x void SeqListInsert(SeqList* psl, size_t pos, SLDataType x); // 顺序表删除pos位置的值 void SeqListErase(SeqList* psl, size_t pos); // 顺序表销毁 void SeqListDestory(SeqList* psl); // 顺序表打印 void SeqListPrint(SeqList* psl); //顺序表修改 void SLModify(SeqList* psl, size_t pos, SLDataType x);
SeqList.c
#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"
// 顺序表初始化
void SeqListInit(SeqList* psl) {
assert(psl);
psl->capicity = 0;
psl->size = 0;
psl->array = NULL;
}
//顺序表打印
void SeqListPrint(SeqList* psl) {
assert(psl);
for (int i = 0; i < psl->size; i++) {
printf("%d ", psl->array[i]);
}
}
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x) {
assert(psl);
//检查空间是否足够
CheckCapacity(&psl);
int temp_size = psl->size;
while (temp_size > 0) {
psl->array[temp_size] = psl->array[temp_size-1];
temp_size--;
}
psl->array[0] = x;
psl->size++;
}
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x) {
assert(psl);
//检查空间是否足够
CheckCapacity(&psl);
psl->array[psl->size] = x;
psl->size++;
}
// 顺序表销毁
void SeqListDestory(SeqList* psl) {
assert(psl);
free(psl->array);
psl->array = NULL;
psl->capicity = 0;
psl->size = 0;
}
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList** psl) {
if ((*psl)->capicity == 0) {
SLDataType* temp = NULL;
(*psl)->capicity = 4 * sizeof(SLDataType);
temp = (SLDataType)malloc((*psl)->capicity);
if (temp == NULL) {
perror(CheckCapacity);
return 0;
}
(*psl)->array = temp;
return;
}
if ((*psl)->capicity <= (*psl)->size*sizeof(SLDataType)) {
(*psl)->capicity *= 2;
SLDataType* temp = NULL;
//检查开辟是否成功
temp = (SLDataType)realloc((*psl)->array,(*psl)->capicity);
if (temp == NULL) {
perror(CheckCapacity);
return 0;
}
(*psl)->array = temp;
}
}
// 顺序表尾删
void SeqListPopBack(SeqList* psl) {
assert(psl);
psl->size--;
}
// 顺序表头删
void SeqListPopFront(SeqList* psl) {
assert(psl);
int temp_size = 1;
while (temp_size <= psl->size) {
psl->array[temp_size-1] = psl->array[temp_size];
temp_size++;
}
psl->size--;
}
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x) {
assert(psl);
//找到返回下标
for (int i = 0; i < psl->size; i++) {
if (psl->array[i] == x) {
return i;
}
}
//没找到返回-1;
return -1;
}
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos) {
assert(psl);
assert(pos < psl->size);
if (pos >= psl->size) {
printf("删除超出范围限制");
return ;
}
while (pos < psl->size) {
psl->array[pos] = psl->array[pos + 1];
pos++;
}
psl->size--;
}
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x) {
assert(psl);
assert(pos <= psl->size);
CheckCapacity(&psl);
int temp = psl->size;
while (temp > pos) {
psl->array[temp] = psl->array[temp - 1];
temp--;
}
psl->array[pos] = x;
psl->size++;
}
//修改
void SLModify(SeqList* psl, size_t pos, SLDataType x) {
assert(psl);
assert(pos < psl->size);
psl->array[pos] = x;
}
二.单链表
单链表.h
#pragma once #include#include #include typedef int SLTDateType; typedef struct SListNode { SLTDateType data; struct SListNode* next; }SListNode; // 动态申请一个结点 SListNode* BuySListNode(SLTDateType x); // 单链表打印 void SListPrint(SListNode* plist); // 单链表尾插 void SListPushBack(SListNode** pplist, SLTDateType x); // 单链表的头插 void SListPushFront(SListNode** pplist, SLTDateType x); // 单链表的尾删 void SListPopBack(SListNode** pplist); // 单链表头删 void SListPopFront(SListNode** pplist); // 单链表查找 SListNode* SListFind(SListNode* plist, SLTDateType x); // 单链表在pos位置之后插入x // 分析思考为什么不在pos位置之前插入? void SListInsertAfter(SListNode* pos, SLTDateType x); // 单链表 之前插入(难) void SListInsertBefore(SListNode* pos, SLTDateType x); // 单链表删除pos位置之后的值 // 分析思考为什么不删除pos位置? void SListEraseAfter(SListNode* pos); // 单链表销毁 void SLlistDestory(SListNode* phead); //单链表删除当前位置 void SListErase(SListNode* pos);
单链表.c
#define _CRT_SECURE_NO_WARNINGS
#include"单链表.h"
SListNode* BuySListNode(SLTDateType x) {
SListNode* temp = (SListNode*)malloc(sizeof(SListNode));
if (temp == NULL) {
perror("malloc fail");
exit(-1);
}
SListNode* newnode = temp;
temp = NULL;
newnode->data = x;
newnode->next = NULL;
return newnode;
}
// 单链表打印
void SListPrint(SListNode* phead) {
SListNode* cur = phead;
while (cur) {
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULLn");
}
// 单链表的头插
void SListPushFront(SListNode** pphead, SLTDateType x) { //改变一级指针就需要一级指针的地址,所以传入二级指针
assert(pphead);
SListNode* newnode = BuySListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
// 单链表尾插
void SListPushBack(SListNode** pphead, SLTDateType x) {
assert(pphead);
//单链表不为空
if (* pphead == NULL ) {
SListNode* next = BuySListNode(x);
*pphead = next;
}//单链表为空
else {
SListNode* cur = *pphead;
while (cur->next != NULL) {
cur = cur->next;
}
SListNode* next = BuySListNode(x);
cur->next = next;
}
}
// 单链表头删
void SListPopFront(SListNode** pphead) {
assert(pphead);
if (*pphead == NULL) {
return;
}
SListNode* del = *pphead;
*pphead = (*pphead)->next;
free(del);
del = NULL;
}
// 单链表的尾删
void SListPopBack(SListNode** pphead) {
assert(pphead);
if (*pphead == NULL) {
return;
}
if ((*pphead)->next == NULL) {
free(*pphead);
*pphead = NULL;
return;
}
SListNode* cur = *pphead;
while (cur->next->next != NULL) {
cur = cur->next;
}
free(cur->next);
cur->next = NULL;
}
// 单链表查找
SListNode* SListFind(SListNode* pphead, SLTDateType x) {
assert(pphead);
SListNode* cur = pphead;
while (cur) {
if (x == cur->data) {
printf("找到了n");
return cur;
}
else {
cur = cur->next;
}
}
return NULL;
}
//单链表在某位置之后插入
void SListInsertAfter(SListNode** pphead,SListNode* pos, SLTDateType x) {
assert(pphead);
if (*pphead == NULL) {
SListPushFront(pphead, x);
return;
}
SListNode* newcode = BuySListNode(x);
newcode->next = pos->next;//注意这两行的顺序
pos->next = newcode;
}
// 单链表 之前插入(难)
void SListInsertBefore(SListNode** pphead, SListNode* pos, SLTDateType x) {
assert(pos);
assert(pphead);
if (*pphead == NULL) {
SListPushFront(pphead, x);
return;
}
//方法一:找到前一项的next
SListNode* cur = *pphead;
if (pos == pphead) {
SListPushFront(pphead, x);
return;
}
while (cur->next != pos) {
cur = cur->next;
//找不到,说明pos传错了
assert(cur);
}
SListNode* newcode = BuySListNode(x);
newcode->next = pos;
cur->next = newcode;
//方法二 顺序法交换
//SListNode* newcode = BuySListNode(pos->data);
//pos->data = x;
}
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode** pphead, SListNode* pos) {
assert(pphead);
assert(pos);
if (pos->next == NULL) {
SListPopBack(pphead);
return;
}
SListNode* cur = pos->next;
pos->next = pos->next->next;
free(cur);
}
//单链表删除当前位置
void SListErase(SListNode** pphead, SListNode* pos) {
assert(pphead && pos);
if (pos == *pphead) {
SListPopFront(pphead);
return;
}
SListNode* cur = pos->next->next;
pos->data = pos->next->data;
free(pos->next);
pos->next = cur;
}
// 单链表销毁
void SLlistDestory(SListNode** pphead) {
assert(pphead);
SListNode* cur = pphead;
SListNode* next = pphead;
while (cur) {
next = cur->next;
free(cur);
cur = next;
}
pphead = NULL;
}
三.带头双向循环链表
List.h
#pragma once #include#include #include typedef int LTDataType; typedef struct ListNode { LTDataType _data; struct ListNode* next; struct ListNode* prev; }ListNode; // 创建返回链表的头结点. ListNode* ListCreate(); //双向链表创造一个新节点 ListNode* ListBuyNode(LTDataType x); // 双向链表打印 void ListPrint(ListNode* plist); // 双向链表尾插 void ListPushBack(ListNode* plist, LTDataType x); // 双向链表头插 void ListPushFront(ListNode* plist, LTDataType x); // 双向链表尾删 void ListPopBack(ListNode* plist); // 双向链表头删 void ListPopFront(ListNode * plist); // 双向链表查找 ListNode* ListFind(ListNode* plist, LTDataType x); // 双向链表在pos的前面进行插入 void ListInsert(ListNode* pos, LTDataType x); // 双向链表删除pos位置的结点 void ListErase(ListNode* pos); // 双向链表销毁 void ListDestory(ListNode* plist);
List.c
#define _CRT_SECURE_NO_WARNINGS
#include"List.h"
// 创建返回链表的头结点.
ListNode* ListCreate() {
ListNode* ListGuard = (ListNode*)malloc(sizeof(ListNode));
if (ListGuard == NULL) {
perror("ListGuard malloc fai");
exit(-1);
}
ListGuard->next = ListGuard;
ListGuard->prev = ListGuard;
return ListGuard;
}
// 双向链表打印
void ListPrint(ListNode* plist) {
assert(plist);
ListNode* head = plist;
ListNode* cur = head->next;
printf("head<=>");
while (cur != head) {
printf("%d<=>", cur->_data);
cur = cur->next;
}
printf("n");
}
//双向链表创造一个新节点
ListNode* ListBuyNode(LTDataType x) {
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
if (newNode == NULL) {
perror("newNode malloc fail");
exit(-1);
}
newNode->next = NULL;
newNode->prev = NULL;
newNode->_data = x;
return newNode;
}
// 双向链表尾插
void ListPushBack(ListNode* plist, LTDataType x) {
assert(plist);
ListNode* tail = plist->prev;
ListNode* newNode = ListBuyNode(x);
//节点四步走 注意语句顺序!
newNode->next = plist;
plist->prev = newNode;
tail->next = newNode;
newNode->prev = tail;
}
// 双向链表头插
void ListPushFront(ListNode* plist, LTDataType x) {
assert(plist);
ListNode* first = plist->next;
ListNode* newNode = ListBuyNode(x);
//节点四步走 注意语句顺序!
first->prev = newNode;
newNode->next = first;
plist->next = newNode;
newNode->prev = plist;
}
//检查双向列表是否为空
int CheckList(ListNode* plist) {
assert(plist);
//返回“真”为空 返回"假"为非空;
return plist->next == plist->prev;
}
// 双向链表尾删
void ListPopBack(ListNode* plist) {
assert(plist);
assert(!CheckList(plist));
ListNode* tail = plist->prev;
//节点链接
tail->prev->next = plist;
plist->prev = tail->prev;
//释放
free(tail);
}
// 双向链表头删
void ListPopFront(ListNode* plist) {
assert(plist);
assert(!CheckList(plist));
ListNode* first = plist->next;
//节点链接
plist->next = first->next;
first->next->prev = plist;
//释放
free(first);
}
// 双向链表查找
ListNode* ListFind(ListNode* plist, LTDataType x) {
assert(plist);
if (CheckList(plist)) {
printf("链表为NULL,无法查找有效数据n");
exit(-1);
}
ListNode* cur = plist->next;
while (cur != plist) {
if (cur->_data == x) {
printf("找到啦n");
return cur;
}
cur = cur->next;
}
return NULL;
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x) {
assert(pos);
ListNode* first = pos->prev;
ListNode* second = pos;
ListNode* newNode = ListBuyNode(x);
newNode->next = second;
second->prev = newNode;
first->next = newNode;
newNode->prev = first;
}
// 双向链表删除pos位置的结点
void ListErase(ListNode* pos) {
assert(pos);
ListNode* first = pos->prev;
ListNode* del = pos;
ListNode* second = pos->next;
first->next = second;
second->prev = first;
free(del);
}
// 双向链表销毁
void ListDestory(ListNode* plist) {
assert(plist);
ListNode* cur = plist->next;
ListNode* next = NULL;
plist->next = NULL;
while (cur != NULL) {
next = cur->next;
free(cur);
cur = next;
}
printf("销毁成功n");
}
四、顺序表、链表 oj
顺序表
1. 原地移除数组中所有的元素 val ,要求时间复杂度为 O(N) ,空间复杂度为 O(1) 。 力扣 2. 删除排序数组中的重复项。 力扣 3. 合并两个有序数组。力扣
链表
1. 删除链表中等于给定值 val 的所有结点 力扣 2. 反转一个单链表。 力扣 3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则 返回第二个中间结点。 力扣 4. 输入一个链表,输出该链表中倒数第 k 个结点。 链表中倒数第k个结点_牛客题霸_牛客网 5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有 结点组成的。 力扣 6. 编写代码,以给定值 x 为基准将链表分割成两部分,所有小于 x 的结点排在大于或等于 x 的结 点之前 。 链表分割_牛客题霸_牛客网 7. 链表的回文结构。 链表的回文结构_牛客题霸_牛客网 8. 输入两个链表,找出它们的第一个公共结点。 力扣 9. 给定一个链表,判断链表中是否有环。 力扣 【思路】 快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行, 如果链表 带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操作跑步减 肥。 10. 给定一个链表,返回链表开始入环的第一个结点。 如果链表无环,则返回 NULL 力扣 11. 给定一个链表,每个结点包含一个额外增加的随机指针,该指针可以指向链表中的任何结点 或空结点。 要求返回这个链表的深度拷贝。 力扣 12. 其他 。 ps :链表的题当前因为难度及知识面等等原因还不适合我们当前学习,以后大家自己 下去以后 力扣 + 牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网顺序表优点: 1.尾插、尾删效率高。 2.可以随机访问。. (了解)3.cpu高速缓存命中率更高(相比链表) 顺序表缺点: 1.头部中部插入效率低——O(N) 2.扩容 ——性能消耗,空间浪费
链表优点: 1.任意插入删除都很方便 2.扩容——不存在空间浪费(按需申请空间) 链表缺点: 1.扩容——每次都要申请malloc浪费了时间 2.不能随机访问