目录
线性表中的数据都像是被串起来一样,具有单一线性关系
一、顺序表
思想:在内存中数据连续存储
这就是一块连续存储的数据。
(一)非动态版本
#define MAX_CAPACITY 100 //定义存储上限
#include<stdio.h>
#include<stdlib.h>
typedef struct Sequencechart
{
int p[MAX_CAPACITY]; //创建一个数组存储数据
int sz; //表示已存数量
}S;
void Initchart(S*pf)
{
pf->p[MAX_CAPACITY] = 0; //存储数据初始化为0
pf->sz = 0; //存储数量为0
}
int checkcapacity(S*pf)
{
if (pf->sz == MAX_CAPACITY) //检查是否超过上限
return 0;
else
return 1;
}
void Add(S*pf, int n)
{
checkcapacity(pf);
pf->p[pf->sz] = n; //sz可作为下标
pf->sz++;
}
int Delete(S*pf, int n)
{
if (!pf->sz) //顺序表为空,返回0
return 0;
for (int i = n - 1; i < pf->sz - 1; i++) //删除某个数据后,要将后面的数向前移动
pf->p[i] = pf->p[i + 1];
pf->sz--;
return 1;
}
int Check(S*pf, int n)
{
if (!pf->sz)
return 0;
for (int i = 0; i < pf->sz; i++)
{
if (n == pf->p[i])
{
printf("找到了,下标为%d\n", i); //查找某数据是否存在。
}
}
return 1;
}
int Modify(S*pf, int n, int ps) //传入修改数据,下标
{
if (!pf->sz)
return 0;
if (ps > pf->sz)
return -1;
pf->p[ps] = n;
return 1;
}
int main()
{
S s;
Initchart(&s);
for (int i = 0; i < 9; i++)
Add(&s, i + 1);
for (int i = 0; i < s.sz; i++)
printf("%d ", s.p[i]);
printf("\n");
Delete(&s, 5);
for (int i = 0; i < s.sz; i++)
printf("%d ", s.p[i]);
printf("\n");
Modify(&s, 777, 2);
for (int i = 0; i < s.sz; i++)
printf("%d ", s.p[i]);
printf("\n");
Check(&s, 777);
return 0;
}
(二)动态版本
注:当初始空间不足以扩增至所需时,realloc会重新选择一块空间并将原数据拷贝过来
#define INITCAPACITY 3 //初始容量
#define ADDNUM 2 //每次扩增的大小
#include<stdio.h>
#include<stdlib.h>
typedef struct Sequencechart
{
int*p; //用指针指向内存空间
int capacity; //当前容量大小
int sz;
}S;
int Initchart(S*pf)
{
pf->capacity = INITCAPACITY;
pf->p = malloc(sizeof(int)*(pf->capacity)); //初始开辟空间
pf->sz = 0;
return 1;
}
int checkcapacity(S*pf)
{
if (pf->sz == pf->capacity) //达到当前容量后扩增
{
pf->capacity += ADDNUM;
pf->p= realloc(pf->p, sizeof(int)*pf->capacity); //realloc第一个参数为指向待扩增空间的指针,即地址,第二个为扩增后的大小,为字节数。
}
return 1;
}
int Add(S*pf, int n)
{
checkcapacity(pf);
pf->p[pf->sz] = n;
pf->sz++;
return 1;
}
int Delete(S*pf, int n)
{
if (!pf->sz)
return 0;
for (int i = n - 1; i < pf->sz - 1; i++)
pf->p[i] = pf->p[i + 1];
pf->sz--;
return 1;
}
int Check(S*pf, int n)
{
if (!pf->sz)
return 0;
for (int i = 0; i < pf->sz; i++)
{
if (n == pf->p[i])
{
printf("找到了,下标为%d\n", i);
}
}
return 1;
}
int Modify(S*pf, int n,int ps)
{
if (!pf->sz)
return 0;
if (ps > pf->sz)
return -1;
pf->p[ps] = n;
return 1;
}
int main()
{
S s;
Initchart(&s);
for (int i = 0; i < 9; i++)
Add(&s, i + 1);
for (int i = 0; i <s.sz; i++)
printf("%d ", s.p[i]);
printf("\n");
Delete(&s, 5);
for (int i = 0; i < s.sz; i++)
printf("%d ", s.p[i]);
printf("\n");
Modify(&s, 777, 2);
for (int i = 0; i < s.sz; i++)
printf("%d ", s.p[i]);
printf("\n");
Check(&s, 777);
free(s.p);
return 0;
}
学会了基本的顺序表后就可以写通讯录这样的小程序了。
二、链表
思想:在内存中数据可以不连续存储,用指针寻找下一个或上一个元素
L*SetLinkList(int n) //创建链表
{
L*head = NULL, *end = NULL;
for (int i = 0; i < n; i++)
{
L*node = (L*)malloc(sizeof(L));
node->data = i;
node->next = NULL;
if (!head)
head =end= node;
else
{
end->next = node;
end = node;
}
}
return head;
}
void*Headinsert(L*p, int val) //头插数据
{
L*node = (L*)malloc(sizeof(L));
node->data = val;
node->next = p;
p = node;
}
L*Reverse(L*p) //翻转链表
{
L*newhead = NULL, *node = NULL;
while (p)
{
node = p;
p = p->next;
node->next = newhead;
newhead = node;
}
return newhead;
}
(一)单链表
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef struct LinkList
{
int data;
struct LinkList*next;
}L;
L*SetLinkList(int n) //创建链表
{
L*head = NULL, *end = NULL;
for (int i = 0; i < n; i++)
{
L*node = (L*)malloc(sizeof(L));
node->data = i;
node->next = NULL;
if (!head)
head =end= node;
else
{
end->next = node;
end = node;
}
}
return head;
}
L*Addnode(L*p, int val, int n)
{
L*prev = p;
L*cur = p;
while (n--)
{
prev = cur;
cur = cur->next;
}
L*node = (L*)malloc(sizeof(L));
node->data = val;
prev->next = node;
node->next = cur;
return p;
}
void*Headinsert(L*p, int val) //头插数据
{
L*node = (L*)malloc(sizeof(L));
node->data = val;
node->next = p;
p = node;
}
L*Delete_fdata(L*p, int val)//数据查找
{
if (p->data == val)
{
p = p->next;
return p;
}
L*prev = p;
L*cur = p;
while (cur->data != val)
{
prev = cur;
cur = cur->next;
}
prev->next = cur->next;
free(cur);
cur = NULL;
return p;
}
L*Delete_index(L*p, int n)//下标查找
{
if (n == 1)
{
p = p->next;
return p;
}
L*prev = p;
L*cur = p;
while (n--)
{
if (!cur)
{
prev->next = NULL;
return p;
}
prev = cur;
cur = cur->next;
}
prev->next = cur->next;
free(cur); //开辟的内存空间一定要释放,防止内存泄漏
cur = NULL;
return p;
}
int Find_fdata(L*p, int val)//数据查找
{
L*cur = p;
int index = 0;
while (cur->data != val)
{
cur = cur->next;
index++;
}
return index;
}
L*Find_index(L*p, int n)//下标查找
{
L*cur = p;
while (n--)
{
cur = cur->next;
}
return cur;
}
L*Modify(L*p, int val, int n)
{
L*cur = p;
Find_index(p, n)->data = val;
return p;
}
L*Reverse(L*p) //翻转链表
{
L*newhead = NULL, *node = NULL;
while (p)
{
node = p;
p = p->next;
node->next = newhead;
newhead = node;
}
return newhead;
}
(二)双向链表
在单链表的基础上增加了一个指向前一个数据的指针
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef struct LinkList
{
int data;
struct LinkList*prev;
struct LinkList*next;
}L;
L*SetLinkList(int n)
{
L*head = NULL, *end = NULL;
for (int i = 0; i < n; i++)
{
L*node = (L*)malloc(sizeof(L));
node->data = i;
node->prev = node->next = NULL;
if (!head)
head = end = node;
else
{
node->prev = end; //让prev指针指向上一次的end
end->next = node;
end = node;
}
}
return head;
}
L*Search(L*p, int index)
{
L*cur = p;
while (index--)
{
cur = cur->next;
}
return cur;
}
L*Headadd(L*p,int val) //头插节点
{
L*node = (L*)malloc(sizeof(L));
node->data = val;
node->next = p;
p->prev = node;
node->prev = NULL;
return node;
}
void Add(L*p, int index,int val)
{
L*cur = Search(p, index);
L*node = (L*)malloc(sizeof(L));
node->data = val;
node->next = cur->next;
cur->next->prev = node;
cur->next = node;
node->prev = cur;
}
void Delete(L*p, int index)
{
L*cur = p;
while (index--)
{
cur = cur->next;
}
cur->prev->next = cur->next; //删除时也要注意prev指针
cur->next->prev = cur->prev;
free(cur);
cur=NULL;
}
void Modify(L*p,int val,int index)
{
L*cur = Search(p, index);
cur->data = val;
}
双向链表就不用费劲逆序了
三、栈
思想:先入的数据放在栈底,后入的放在栈顶,遵循先入后出,即FILO(first in last out)
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#define INITCAPACITY 10 //栈的初始容量
typedef int STD; //为数据类型起一个别名,代表栈的数据
typedef struct Stack
{
STD*base; //栈底为指向内存空间的指针
STD top; //栈顶可代表下标,这里用数组实现栈,当然还有别的方法
int capacity; //栈的当前容量
}S;
void InitStack(S*pf)
{
pf->base =(int*)malloc(sizeof(int)*INITCAPACITY); //初始空间
pf->capacity = INITCAPACITY;
pf->top = 0;
}
void checkcapacity(S*pf)
{
assert(pf); //pf为空断言报错,便于查找错误
if (pf->top == pf->capacity)
{
pf->capacity *= 2; //不够增容为原来的两倍
pf->base =(STD*)realloc(pf->base,pf->capacity*sizeof(int));
}
}
//入栈
void StackPush(S*pf, int n)
{
checkcapacity(pf);
pf->base[pf->top] = n;
pf->top++;
}
//出栈
void StackPop(S*pf)
{
assert(pf&&pf->top > 0);
pf->top--; //不必释放空间,再次赋值即可重新利用
}
//判断是否为空栈
bool StackEmpty(S*pf)
{
assert(pf);
if (pf->top == 0)
return true;
else
return false;
}
//释放栈
void StackDestory(S*pf)
{
assert(pf);
pf->capacity = pf->top = 0;
free(pf->base);
pf->base = NULL;
}
//获取栈顶元素
int StackTop(S*pf)
{
assert(pf&&pf->top > 0); //栈顶要大于0才有数据
return pf->base[pf->top - 1];
}
//获取栈内的数据数量
int StackSize(S*pf)
{
assert(pf);
return pf->top;
}
四、队列
思想:先入先出,像通过走廊一样
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QUD;
typedef struct QueueNode //这里用链表实现队列
{
struct QueueNode*next;
QUD data;
}Qnode;
typedef struct Queue
{
Qnode*head;
Qnode*tail;
}Queue;
void QueueInit(Queue*p)
{
assert(p);
p->head = p->tail = NULL;
}
//入队列
void QueuePush(Queue*p, QUD n)
{
assert(p);
Qnode*node = (Qnode*)malloc(sizeof(Qnode));
node->next = NULL;
node->data = n;
if (p->tail == NULL)
{
p->head = p->tail = node;
}
else
{
p->tail->next = node; //用队尾入数据
p->tail = node;
}
}
出队列
void QueuePop(Queue*p)
{
assert(p&&p->head);
if (p->head->next == NULL) //只有一个节点直接free头
{
free(p->head);
p->head = p->tail = NULL;
}
else
{
Qnode*temp = p->head->next; //将下一节点设为头并释放原头内存
free(p->head);
p->head = temp;
}
}
//取队头元素
QUD QueueFront(Queue*p)
{
assert(p&&p->head);
return p->head->data;
}
QUD QueueBack(Queue*p)
{
assert(p&&p->head);
return p->tail->data;
}
//释放队列
void QueueDestory(Queue*p)
{
assert(p);
Qnode*cur = p->head;
while (cur)
{
Qnode*temp = cur->next;
free(cur);
cur = temp;
}
p->head = p->tail = NULL;
}
//判断队列是否为空
bool QueueEmpty(Queue*p)
{
return p->head == NULL;
}
//获取队列中元素的个数
int QueueSize(Queue*p)
{
assert(p);
int size = 0;
Qnode*cur = p->head;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
这里都用了最简单的办法实现栈和队列,先把这四种数据结构的逻辑思想搞懂,再去深入了解其用法和不同的实现方式。