目录
1、线性表
就是n个具有相同特性的数据元素的有限序列。挨着存储的,常见的线性表:顺序表、链表、栈、队列。
2、顺序表
2.1、顺序表概念
顺序表是利用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下用数组存储。在数组上完成数据的增删查改。
顺序表分为:
- 静态顺序表:使用定长数组存储元素
- 动态顺序表:使用动态开辟的数组存储,按需申请
缺点:
- 在头部或中间插入删除数据,需要挪动数据,效率低
- 空间不够,扩容有一定消耗(异地扩容),还可能有一定空间浪费
2.2、顺序表实现
SeqList.h:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
静态顺序表
//#define N 10
//typedef int SLDataType;
//struct SeqList
//{
// SLDataType a[N];
// int size;
// int capacity;
//};
typedef int SLDataType;
#define INIT_CAPACITY 4
typedef struct SeqList
{
SLDataType* a;
int size; //有效数字个数
int capacity;//容量大小
}SL;
//初始化顺序表
void SLInit(SL* ps);
void SLPrint(SL* ps);
//增删查改
void SLPushBack(SL* ps,SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
void SLDestroy(SL* ps);
// 顺序表查找
int SLtFind(SL* ps, SLDataType x);
// 顺序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x);
// 顺序表删除pos位置的值
void SLErase(SL* ps, int pos);
//扩容
void CheckCapacity(SL* ps);
SeqList.c:
#include"SeqList.h"
void SLInit(SL* ps)
{
assert(ps);
ps->a = (SLDataType*)malloc(INIT_CAPACITY * sizeof(SLDataType));
if (ps -> a == NULL)
{
perror("malloc fail");
return;
}
ps->size = 0;
ps->capacity = INIT_CAPACITY;
}
void SLDestroy(SL* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->size = ps->capacity = 0;
}
void SLPrint(SL* ps)
{
assert(ps);
int i = 0;
for (i = 0;i < ps->size;i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
void CheckCapacity(SL* ps)
{
//扩容
if (ps->size == ps->capacity)
{
SLDataType* tmp = (SLDataType*)realloc(ps->a, sizeof(SLDataType) * ps->capacity * 2);
if (tmp == NULL)
{
free(ps->a);
ps->a = NULL;
ps->size = ps->capacity = 0;
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity *= 2;
}
}
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);
CheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
void SLPopBack(SL* ps)
{
assert(ps);
ps->size--;
}
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
CheckCapacity(ps);
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps -> a[0] = x;
ps->size++;
}
void SLPopFront(SL* ps)
{
assert(ps);
//assert(ps->size > 0);
if (ps->size == 0)
{
return;
}
int begin = 0;
while (begin < ps->size-1)
{
ps->a[begin] = ps->a[begin + 1];
begin++;
}
ps->size--;
}
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
int pos = 0;
for (pos = 0;pos < ps->size;pos++)
{
if (ps->a[pos] == x)
{
return pos;
}
}
return -1;//没找到,返回-1
}
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
CheckCapacity(ps);
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[pos] = x;
ps->size++;
}
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
}
3、链表
3.1、链表概念:
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。就是一个结构中除了保存数据,还保存了下个结构的地址,把他们连接起来。
无头单向非循环链表(单链表):就除了有自身的数据,还保存了下个结点的地址。
带头双向循环链表(双链表):不仅存着下个结点的地址,还存着上个结点的地址,head存着最后结点的地址,又存着下个结点的地址。逻辑上结点之间双向循环连接。
3.2、单链表实现:
SList.h:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
// 动态申请一个节点
SLTNode* BuySLTNode(SLTDataType x);
//打印单链表
void SLTPrint(SLTNode* phead);
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
// 单链表的头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
// 单链表的尾删
void SLTPopBack(SLTNode** pphead);
// 单链表头删
void SLTPopFront(SLTNode** pphead);
//单链表查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//pos之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//pos位置删除
void SLTErase(SLTNode** pphead, SLTNode* pos);
//pos位置后面插入
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//pos位置后面删除
void SLTEraseAfter(SLTNode* pos);
//单链表删除
void SLTDestory(SLTNode** pphead);
SList.c:
#include"SList.h"
SLTNode* BuySLTNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail");
return NULL;
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void SLTPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuySLTNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
//找尾
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuySLTNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SLTPopBack(SLTNode** pphead)
{
assert(pphead);
assert(*pphead != NULL);
/*if (*pphead == NULL)
{
return;
}*/
//1、只有一个结点
//2、有多个结点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
//找尾
SLTNode* tail = *pphead;
SLTNode* prev = NULL;
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
prev->next = NULL;
free(tail);
tail = NULL;
}
}
void SLTPopFront(SLTNode** pphead)
{
assert(pphead);
assert(*pphead != NULL);
SLTNode* first = NULL;
first = *pphead;
*pphead = first->next;
free(first);
first = NULL;
}
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
SLTNode* cur = phead;
while (cur != NULL)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
SLTPushFront(pphead,x);
}
else
{
//找到pos前一个位置
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
SLTNode* newnode = BuySLTNode(x);
prev->next = newnode;
newnode->next = pos;
}
}
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
assert(*pphead);
if (*pphead == pos)
{
SLTPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
}
}
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = BuySLTNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
void SLTEraseAfter(SLTNode* pos)
{
assert(pos);
assert(pos->next);
SLTNode* del = pos->next;
pos->next = del->next;
free(del);
del = NULL;
}
void SLTDestory(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* tmp = cur->next;
free(cur);
cur = tmp;
}
*pphead = NULL;
}
3.3、双链表实现
List.h:
//带头双向循环的双链表
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next;
struct ListNode* prev;
LTDataType data;
}LTNode;
//初始化双链表
LTNode* LTInit();
//打印双链表
void LTPrint(LTNode* phead);
//销毁链表
void LTDestroy(LTNode* phead);
//双链表头插
void LTPushFront(LTNode* phead, LTDataType x);
//头删
void LTPopFront(LTNode* phead);
//双链表尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//双向链表查找
LTNode* LTFind(LTNode* phead,LTDataType x);
//在pos之前插入
void LTInsert(LTNode* pos, LTDataType x);
//pos位置删除
void LTErase(LTNode* pos);
List.c:
#include"List.h"
LTNode* BuyLTNode(LTDataType x)
{
LTNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)
{
perror("malloc fail");
return NULL;
}
node->next = NULL;
node->prev = NULL;
node->data = x;
return node;
}
LTNode* LTInit()
{
LTNode* head = BuyLTNode(-1);
head->next = head;
head->prev = head;
return head;
}
void LTPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
printf("<=>head<=>");
while (cur != phead)
{
printf("%d<=>", cur->data);
cur = cur->next;
}
printf("\n");
}
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyLTNode(x);
LTNode* cur = phead;
LTNode* next = phead->next;
//cur newnode next
cur->next = newnode;
newnode->prev = cur;
newnode->next = next;
next->prev = newnode;
}
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
LTNode* cur = phead->next;
LTNode* next = cur->next;
//phead cur next
phead->next = next;
next->prev = phead;
free(cur);
cur = NULL;
}
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyLTNode(x);
LTNode* tail = phead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
LTNode* tail = phead->prev;
LTNode* tailprev = tail->prev;
tailprev->next = phead;
phead->prev = tailprev;
free(tail);
}
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = BuyLTNode(x);
LTNode* posprev = pos->prev;
//posprev newnode pos
posprev->next = newnode;
newnode->prev = posprev;
newnode->next = pos;
pos->prev = newnode;
}
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* posprev = pos->prev;
LTNode* posnext = pos->next;
posprev->next = posnext;
posnext->prev = posprev;
free(pos);
pos = NULL;
}
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}