data structure
list 线性表
- 零个或多个相同类型的数据元素的有限序列
- 有限
- 相同数据类型
顺序存储
#define maxsize 20 // 存储空间
#define init Ele //假设list为 int型
typedef strct{
Ele data[maxsize]; // 可以是其他类型的数组,并规定最大长度
int length// list当前长度
}MyList
// 返回0和1代表有或者没有,也可以返回list 对应类型数据的指针
int getEle(MyList L, int i, Ele *e)
{
if(L.length==0 || i<1 || i>L.length)
retuirn 1;
*e = L.data[i-1];
return 0;
}
int insertEle(MyList *L, int i, Ele e)
{
int k;
if(L->length==maxsize) //list已满
return 1;
if(i<1 || i>L->length+1) //插入位置不在list范围内
return 1;
if(i<=L->length) //若插入数据位置不在list尾部
{
for(k=L.length-1;k>=i-1;k--)
L->data[k+1]=L->data[k]; //将插入位置后面的元素向后移动1位
}
L->data[i-1]=e;
L->length++;
return 0;
}
int deleteEle (MyList *L, int i, Ele *e*)
{
int k;
if (L->length == 0) //如果list为空
return 0;
if (i<1 || i> L->length) // 删除位置不正确
return 0;
if (i< L->length) // 如果删除的不是最后的位置
{
for(k=i; k<L->length; k++) // 删除位置后的元素迁移
L->data[k-1]=L->data[k];
}
L->length--;
return 1;
}
链式存储
- 单链表:只有一个指针域,指向后继节点
- L是链表头结点,(*L)->next 是链表第一个节点;
- 结构定义
typedef struct Node
{
Ele data;
struct Node *next;
}Node;
typedef struct Node *LinkList
int GetEle (LinkList L, int i, Ele *e*)
{
int j;
LinkList p;
p = L->next; // 指向L第一个节点
j = 1;
while(p && j<i) p 不为空并且还没到i节点
{
p=p->next;
++j;
}
if (!p || j>i) // 要查找的第i个元素不存在
return 1;
*e = p->data;
return 0;
}
在L中第i个位置之前插入新的元素e
int insertEle (LinkList *L, int i, Ele e)
{
int j;
LinkList p,s;
p = *L;
j = 1;
while (p && j<i) 寻找第i个节点
{
p = p->next;
++j;
}
if(!p || j>i) // 第i个元素不存在
return 1;
s = (LinkList)malloc(sizeof(Node)) //生成新节点
// 赋值操作
s->data = e;
s->next = p->next;
p->next = s;
return 0;
}
- deleteEle 后操作被插入节点 ,如果知道第i个元素在哪,那么O(1)
删除L的第i个元素,并用e返回其值
int deleteEle (LinkList *L, int i, Ele *e)
{
omt j;
LinkList p,q;
p = *L;
j = 1;
while (p->next && j<i) // 找到第i个元素
{
p = p-next;
++j;
}
if (!(p->next) || j> i) // 第i个元素不存咋
return 1;
// 赋值操作
q = p->next;
p->next = q->next;
*e = q->data; // 保存删除的数据
free(q); // 回收被删除节点
return 0
}
单链表的整表创建和删除
随机生成n个元素,创建带头结点的单链表L
// 头插法
void createEle(LinkList *L, int n)
{
LinkList p;
int i;
srand(time(0)); 随机数种子
*L = (LinkList)malloc(sizeof(Node)); 创建一个带头结点的单链表
(*L) ->next = Null; 创建一个带头结点的单链表
for(i=0; i<n; i++)
{
p = (LinkList)malloc(sizeof(Node)); //创建节点
p->data = rand()%100+1 // 赋值data域
// 新节点插入到第一个节点
p->next = (*L)->next;
(*L) ->next = p;
}
}
// 尾插法
void createEle(LinkList *L, int n)
{
LinkList p,r;
int i;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node));
r=*L;
for(i=0; i<n; i++)
{
p = (LinkList)malloc(sizeof(Node));
p->data = rand()%100+1
r->next = p; //尾结点指向新的节点
r = p; //随着循环,尾结点变成新插入的节点
}
r-next = NULL; //链表结束
]
将线性表清空
int clearEle(LinkList *L)
{
LinkList p,q;
p=(*L)-next; //指向链表第一个节点
while(p) // 循环一直到表尾
{
q = p->next;
free(p);
p=q;
}
(*L)->next=NULL; //头结点指针为空
return 0;
}
静态链表
- 给没有指针或者对象引用的语言,实现链表数据结构
- 用一个类似js数组对象实现,cur表示指针域
- [{data:a,cur:1.{data:b,cur2}]
循环链表
- 快速查找尾结点
- 最后节点的指针由指向null 改为 指向 头节点
- 2个链表合并时
1.记录头节点 p = rearA->next; //这里用rear的方式表示头节点
2.A的尾结点指向B的第一个节点(此时已经不需要B的头节点) rearA->next = rearB->next->next;
3.B的尾结点指向A的头节点 rearB->next = p;
4.free(p)
双向循环链表
- 有两个指针域
- 优势在于反向遍历查找数据结构
- 以空间换时间
- 缺点在于插入和删除需要改变两个指针
- 数据结构
typedef struct douNode
{
Ele data;
struct DouNode * proir; //前继指针
struct DouNode *next; //后继指针
}DouNode
栈
- 基于线性表结构
- 后进先出的线性表
- 只允许在一端插入和删除操作的线性表
- 栈顶和栈底
- 栈顶可以出栈
- 也分顺序存储和链式存储
- 第0个元素为栈底
- 结构
typedef int Ele;
typedef struct
{
Ele data[maxsize];
int top;
}Stack;
int Push (stack *s, Ele e)
{
if (s->top == maxsize -1) //栈满
{
return 1;
}
s->top++;
s->data[s->top] = e;
return 0;
}
删除s栈顶元素,返回值e
int pop (stack *s, Ele *e*)
{
if(s->top == -1)
{
return 1;
}
*e = s->data[s->top];
s-=>top--;
return 0;
}
两个栈共用一个空间结构
typedef struct
{
Ele data[maxsize];
int top1;
int top2;
} douStack;
int push (douStack *s, Ele e, int stackNumber)
{
if(s->top + 1 == s->top2) //栈已满
return 1;
if (stackNumber ==1)
s->data[++s->top1] = e;
else if (stackNumber ==2)
s->data[--s->top2] =e;
return 0;
int pop (douStack *s, Ele *e, int stackNumber)
{
if(stackNumber ==1)
{
if(s->top1 == -1)
return 1;
*e = s->data[s->top1--];
}
else if (stackNumber ==2)
{
if (s->top2 ==maxsize)
return 1;
*e = s->data[s->top2++];
}
return 0;
}