大话数据结构
逻辑结构–>
集合结构
线性结构
树形结构
图形结构
物理结构-》存储结构
顺序存储结构—数组
链式存储结构—
抽象数据类型是对实际生活中的问题隐藏并且分解为多个规模较小并且容易处理的问题。
算法的特性
输入输出
有穷性
确定性
可行性
顺序表存储结构
#define MAXSIZE 20
typedef int ElemType;
typedef struct
{
ElemType data[MAXSIZE];
int length;
}SqList;
顺序表获得元素
Status GetElem(SqList L,int i,ElemType *e){
if(L.length0||i<1||i>L.length)
return ERROR;
*e=L.data[i-1];
return OK;
}
Status OK->1 ERROR->0
顺序表插入元素:
Struct ListInsert(SqList *L,int i,ElemType e)
{
int k;
if(L->lengthMAXSIZE)
return ERROR;
if(i<1||i>L->length+1)
return ERROR;
if(i<=L->length){
//插入的元素不在表尾
for(k=L->length-1;k>=i-1;k–)//插入位置后的数据元素后移动一位
L->data[k+1]=L->data[k];
}
L->data[i-1]=e;//将新元素插入
L->length++;
return OK;
};
删除顺序表操作
Status ListDelete(SqList *L,int i,ElemType *e){
int k;
if(L->length==0)
return ERROR;
if(i<1||i>L->length)
return ERROR;
*e=L->data[i-1];
if(ilength){
for(k=i;klength;k++)//将删除位置后继元素前移
L->data[k-1]=L->data[k];
}
L->length–;//长度减1
return OK;
}
单链表的存储结构
typedef struct Node
{
ElemType data;
Struct Node *next;
}Node;
typedef struct Node *LinkList;//定义链表
p->data的值是一个数据元素
p->next的值识一个指针
获取链表第i个数据的思路:
Status GetElem(LinkList L,int i,ElemType *e){
int j;
LinkList p;//声明一个节点
p=L->next; //p指向L的第一个节点
j=1;//j为计数器
while(p&&j<i){
p=p->next;//p指向下一个节点
++j;
}
if(!p||j>i)
return ERROR;
*e=p->data;
return OK;
}
在第i个位置之前插入新的元素e L长度加1
Status LinkInsert(LinkList *L,int i,ElemType 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 ERROR;
s=(LinkList)malloc(sizeof(Node));//动态生成新的节点
s->data=e;//先连接后面
s->next=p->next;//在连接前面
//如果顺序搞反就造成s->next=s;
return OK;
}
删除节点
p->next=p->next->next;
就是直接把需要删除的节点绕过去即可
Status ListDelete(LinkList *L,int i,ElemType *e){
int j;
LinkList p,q;
p=*L;
j=1;
while(p->next&&j<i){//遍历寻找第i个元素
p=p->next;
++j;
}
if(!(p->next)||j>i)
return ERROR;//当第i个元素不存在
p->next=p->next->next;
*e=p->next->data;
free(p->next);
return OK;
}
//头插法建立单链表
void CreateListHead(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;
p->next=(*L)->next;
(*L)->next=p;//插入到表头
}
}
尾插法
删除链表就是不停的把当前节点赋值过去然后删除
Status CreateList(LinkList *L){
LinkList p,q;
p=(*L)->next;
while§{
q=p->next;
free§;
p=q;
}
(*L)->next=NULL;
return OK;
}
循环链表个单链表的差异就是在于循环条件的判断上
p->next=NULL;表示单链表
p->next=head;表示循环链表
如何合并两条循环链表
p=rearA->next;//保存A表的头结点
rearA->next=rearB->next->next;//把B的头结点的下一个节点赋值给A的头结点,a的尾节点赋值给b的头结点
rearB->next=p;//将A的头结点连接到b的尾节点后面
free§;
Stack
InitStack(*S)😕/栈初始化操作
DestroyStack(*S);//销毁栈
ClearStack(*S);//栈清空
Push(*S,e);//栈s存在,插入新元素e到栈s中成为栈顶元素
Pop(*S,*e);//删除栈顶元素
//栈结构定义
typedef int SElemType;
typedef struct{
SElemType data[MAXSIZE];
int top;//用于栈顶指针
}SqStack;
//进栈操作
//插入一个元素e为新的栈顶元素
Status Push(SqStack *S,SElemType e){
if(S->top==MAXSIZE-1)//栈满
{
return ERROR;
}
S->top++;//栈顶指针先增加1
S->data[S->top]=e;//将新输入的元素复制给栈顶空间
return OK;
}
//出栈操作
//栈不为空,删除S的栈顶元素,用e返回
Status Pop(SqStack *S,SElemType *e){
if(S->top==-1)
return ERROR;
*e=S->data[S->top];//将要删除的栈顶元素复制给e
S->top–;//栈顶指针减一
return OK;
}
//共享站初始化代码
typedef struct
{
SElemType data[MAXSIZE];
int top1;
int top2;
}SeDoubleStack;
//插入元素e为新的栈顶元素
Status Push(SeDoubleStack *S,SElemType e,int stackNumber){
if(S->top1+1S->top2)//栈已经满,不能push
return ERROR;
if(stackNumber1)//元素进第一个栈
S->data[++S->top1]=e;//栈1先+1后在给数组元素赋值
else if(stackNumber==2);//元素进第二个栈
S->data[–S->top2]=e;//栈2是需要先减少在给数组赋值
return OK;
}
//共享栈删除元素
Status Pop(SeDoubleStack *S,SElemType *e,int stackNumber){
if(stackNumber1){
if(S->top1-1)
return ERROR; //栈1是空栈,溢出
*e=S->data[S->top1–];//将栈1的栈顶元素出栈
}
else if(stackNumber2){
if(S->top2MAXSIZE)
return ERROR;
*e-S->data[S->top2++];//栈2栈顶元素出栈
}
return OK;
}
链栈的结构体
typedef struct StackNode{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;
//链栈插入元素e
Status Push(LinkStack *S,SElemType e){
LinkStack s=(LinkStackPtr)malloc(sizeof(StackNode));
s->data=e;
s->next=S->top;//把当前栈顶元素赋值给直接后继
S->top=s;
S->count++;
return OK;
}
//出栈操作
Status Pop(LinkStack *S,SElemType *e){
LinkStackPtr p;
if(StackEmpty(*s))
return ERROR;
*e=S->top->data;
p=S->top;//把顶节点赋值给p
S->top=S->top->next;//栈顶指针直接指向下一个
free§;
S->count–;
return OK;
}
栈的应用->递归
迭代是使用循环结构
递归是使用选择结构
循环队列顺序存储结构代码:
typedef int QElemType;
typedef struct{
QElemType data[MAXSIZE];
int front;//头指针
int rear;//尾指针
}SqQueue;
//循环队列初始化
Status InitQueue(SqQueue *Q){
Q->front=0;
Q->rear=0;
return OK;
}
//循环队列求队列长度
//返回q的元素个数也就是队列当前的长度
int QueueLength(SqQueue Q){
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
//循环队列的入队操作:
//队列未满,插入元素为新的队尾
Status EnQueue(SqQueue *Q,QElemType e){
if((Q->rear+1)%MAXSIZE==Q->front)//队满的判断
return ERROR;
Q->data[Q->rear]=e;//将元素e赋值给队尾
Q->rear=(Q->rear+1)%MAXSIZE;// rear指针向后移一位
return OK;
}
//循环链表出队操作
Status DeQueue(SqQueue *Q,QElemType *e){
//队列,元素
if(Q->front==Q->rear)
return ERROR;
*e=Q->Data[Q->front];
Q->front=(Q->front+1)%MAXSIZE;
return OK;
}
//队列链式存储结构出队操作
循环队列必须有一个固定的长度,所以才有了存储元素个数和空间浪费的问题
出队是头指针右移一位,出队只头指针右移一位
链队列只需要申请一个指针域,会产生空间上的浪费
5、串
//返回子串在S中位置,否则返回0
int Index(String S,String T,int pos){
int n,m,i;
String sub;
if(pos>0){
n=StrLength(S);//主串长度S
m=StrLength(T);//子串长度T
i=pos;
while(i<=n-m+1){
SubString(sub,S,i,m);//取主串的第i的位置
if(StrCompare(sub,T)!=0)//如果两个串不相等
++i;
else
return i;
}
}
return 0;
}
朴素的模式匹配算法,
就是对主串做大循环,对子串做T长度的小循环,直至完全匹配成功
思路:返回子串在主串s中的第pos个字符之后的位置。若不存在,则返回值为0
int Index(String S,String T,int pos){
int i=pos;//i在主串s中当前位置下标
int j=1;//j在子串T当中的下标
while(i<=S[0]&&j<=T[0]){
if(S[i]==T[j]){
++i;
++j;
}
else{//指针后退重新开始匹配
i=i-j+2;//i退回到匹配首位的下一位
j=1;//j退回到子串T的首位
}
}
if(j>T[0])
reurn i-T[0];
else
return 0;
}
KMP算法
主串S=“abcdefgab”
子串T=“abcdex”
正常匹配流程:
主串S=“abcdefgab”
子串T=" abcdex"
主串S=“abcdefgab”
子串T=" abcdex"
主串S=“abcdefgab”
子串T=" abcdex"
主串S=“abcdefgab”
子串T=" abcdex"
主串S=“abcdefgab”
子串T=" abcdex"
都是多余的