数据结构笔记——c++语言版

基本操作

InitList(&L)

InitList(&L)
{
}
//操作结果:构造一个空的线性表L

CreatList(&L,n)

void CreateList(LinkList &L, int n)
{
    L = new LNode; L->next = Null;
    r = L;//尾指针r指向头结点
    for(i = 0;i < n;++i)
    {
        p = new LNode;
        cin >> p->data;//生成新结点,输入元素值
        p->next = NULL;
        r->next = p;//插入到表尾
        r = p;//r指向新的尾结点
    }
}
//正位序输入n个元素的值,建立带表头结点的单链表L

DestroyList(&L)

DestroyList(&L)
{
}
//初始条件:线性表L已经存在
//操作结果:销毁线性表L

ClearList(&L)

ClearList(LinkList &L)
{
    LinkList *p,*q;
    p=L->next;
    while(p)
    {
        q = p->next;
        delete p;
        p = q;
    }
    L->next = NULL;
    return OK;
}
//初始条件:线性表L已经存在
//操作结果:将线性表L重置为空表

ListEmpty(L)

ListEmpty(L)
{
}
//初始条件:线性表L已经存在
//操作结果:若线性表L为空表,则返回TRUE;否则返回FALSE

ListLength(L)

ListLength(LinkList L)
{
    LinkList p;
    p = L->next;
    i = 0;
    while(p)
    {
        i++;
        p = p->next;
    }
    return 0;
}
//初始条件:线性表L已经存在
//操作结果:返回线性表L中的数据元素个数

ListDelete(&L,I,&e)

Status ListDelete(LinkList &L,int i,ElemType &e)
{
    p = L; j = 0;
    while(p->next && j < i - 1)
    {p = p->next; ++j;}//寻找第i个结点,并令p执行那个其前驱
    if(!(p->next)|| j > i - 1)return ERROR;//删除位置不合理
    q = p->next;//临时保存被删结点的地址以备释放
    p->next = q->next;//改变删除结点前驱结点的指针域
    e = q->data;//保存删除结点的数据域
    delete q;//释放删除结点的空间
    return OK;
}

GetElem(L,i,&e)

Status GetElem(LinkList L,int i,ElemType &e)
{
    p = L->next; j = 1;//初始化
    while(p&&j<i)//向后扫描,直到p指向第i给元素或p为空
    {
        p = p->next;++j;
    }
    if(!p||j>i)
        return ERROR;//第i个元素不存在
    e = p->data;//获取第i个元素
    return OK;
}
//初始条件:线性表L已经存在,1<=i<=ListLength(L)
//操作结果:用e返回线性表L中的第i个数据元素的值

LocateElem(L,e)

int LocateElem(LinkList L,ElemType e,compare)
{
    p = L->next;j = 1;
    while(p && p->data!=e)
    {p = p->next; j++;}
    if(p) return j;
    else return 0;
}
//返回线性表L中值为e的数据元素的位置序号,查找失败返回0

LocateElem(L,e,compare)

LocateElem(LinkList L,ElemType e,compare)
{
}
//初始条件:线性表L已经存在,compare()是数据元素判定函数
//操作结果:返回L中第1个与e满足compare()的数据元素的位序。若这样的数据元素不存在则返回值为0

PriorElem(L, cur_e,&pre_e)

PriorElem(L, cur_e,&pre_e)
{

}
//初始条件:线性表L已经存在
//操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱否则操作失败; pre_e无意义。

NextElem(L, cur_e,&next_e)

NextElem(L, cur_e,&next_e)
{

}
//初始条件:线性表L已经存在。
//操作结果:若cur_e是L的数据元素,且不是第最后个,则用pext_e返回它的后继,否则操作失败, next_e无意义。

ListInsert(&L, i, e)

Status ListInsert(LinkList &L,int i,ElemType e)
{
    p = L;J = 0;
    whiile(p && j < i - 1)
    {p = p->next; ++j;}.//寻找第i-1个结点,p指向i-1结点
    if(!p || j > i - 1)return ERROR;//i大于表长+1或者小于1,插入位置非法
    s = new LNode; s->data = e;//生成新结点s,将结点s的数据域置为e
    s->next = p->next;//将结点s插入线性表L中
    p->next = s;
    return OK;
}
//初始条件:线性表L已经存在,1<=i<= ListLength(L)+1
//操作结果:在L的第i个位置之前插入新的数据元素e, L的长度加一。

ListTraverse(&L, visited())

ListTraverse(&L, visited())
{

}
//初始条件:线性表L已经存在
//操作结果:依次对线性表中每个元素调用visited()

函数结果状态码

#define TRUE    1
#define FALSE   0
#define OK      1
#define ERROR   0
#define INFEASIBLE -1
#define OVERFLOW   -2

函数结果状态代码

typedef int Status;
typedef char ElemType;

线性表

线性表的逻辑次序和物理次序不一定相同

单链表:

在这里插入图片描述

结点只有一个指针域的链表,称为单链表或线性链表

双链表:

结点有两指针域的链表,称为双链表

在这里插入图片描述

循环链表:

首尾相连的链表称为循环链表
在这里插入图片描述

在这里插入图片描述

头指针:指向链表中第一个结点的指针
首元结点:指链表中存储第一个数据元素a1的结点
头结点:是在链表的首元结点之前附设的一个结点
表示空表:
无头结点时,头指针为空时表示空表

在这里插入图片描述

有头结点时,当头结点的指针域为空时表示空表

在这里插入图片描述

在链表中设置头结点有什么好处?

  1. 便于首元结点的处理

首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其它位置一致,无须进行特殊处理

  1. 便于空表和非空表的统一处理

无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一

链表(链式存储结构)的特点

1.结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻。

2.访问时只能通过头指针进入链表,并通过每个结点的指针域依次向后顺序扫描其余结点,所以寻找第一个结点和最后一个结点所花费的时间不等

在这里插入图片描述

在这里插入图片描述

带尾指针循环链表的合并:

LinkList Connect(LinkList Ta,LinkList Tb)
{//假设Ta,Tb都是非空的大黁换链表
    p=Ta->next;//p存表头结点
    Ta->next = Tb->next->next;//Tb表头连结Ta表尾
    delete 	Tb->next;//释放Tb表头结点
    Tb->next = p;//修改指针
    return Tb;
}

双向循环链表:

在这里插入图片描述

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/66638d95c4da43ccaf823a5a47613ad0.jpeg#pic_center)

双向链表的插入:

void ListInsert(LinkList &L,int i, ElemType e)
{//在带头结点的双向链表L中第i个位置之前插入元素e
    if(!(p=GetElem(L,i)))return ERROR;
    s = new LNode; s->data = e;
    s->prior = p->prior;  p->prior->next = s;
    s->next = p;  p->prior = s;
    return OK;
}

双向链表的删除:

void ListDelete(LinkList &L,int i,ElemType e)
{//删除带头结点的双向循环链表L的第i个元素,并用e返回
    if(!(p=GetElem(L,i)))return ERROR;
    e = p->data;
    p->prior->next = p->next;
    p->next->prior = p->prior;
    free(p);
    return OK;
}

栈和队列

栈和队列是限定插入和删除只能在表的“端点进行的线性表”

栈是仅在表尾进行插入、删除操作的线性表
表尾(即an)称为栈顶Top;表头(即a1)称为栈底Base

插入元素到栈顶的操作,称为 入栈 \color{red}{入栈} 入栈
从栈顶删除最后一个元素的操作,称为 出栈 \color{red}{出栈} 出栈

运算规则:
后进先出 \color{green}{后进先出} 后进先出

栈的一般定义

#define MAXSIZE 100
typedef struct{
    SElemType *base;//栈底指针
    SelemType *top;//栈顶指针
    int stacksize;//栈可用最大容量
}SqStack;

InitStack(&S)

Status InitStack(SqStack &S)//初始化栈
{
    S.base = new SElemType[MAXSIZE];
    if(!S.base)exit(OVERFLOW);//存储分配失败
    S.top = S.base;//栈顶指针等于栈底指针
    S.stacksize = MAXSIZE;
    return OK;
}
//操作结果:构造一个空栈S

DestroyStack(&S)

DestroyStack(&S)//销毁栈
{
    if(S.base){
        delete S.base;
        S.stacksize = 0;
        S.base = S.top = NULL;
    }
    return OK;
}
//初始条件:栈S已存在
//操作结果:栈S被销毁

ClearStack(S)

Status ClearStack(SqStack S){
    if(S.base)S.top = S.base;
    return OK;
}

StackEmpty(S)

Status StackEmpty(SqStack S)//判断S是否为空栈
{
    if(S.top == S.base)
        return TRUE;
    else
        return FALSE;
}
//初始条件:栈S已存在
//操作结果:若栈S为空栈,则返回TRUE,否则FALSE

StackLength(S)

StackLength(S)//求栈的长度
{
    
}
//初始条件:栈S已存在
//操作结果:返回S的元素个数,即栈的长度。

GetTop(S,&e)

GetTop(S,&e)//去栈顶元素
{
    
}
//初始条件:栈S已存在且非空
//操作结果:用e返回S的栈顶元素

ClearStack(&S)

ClearStack(&S)//清空栈
{
    
}
//初始条件:栈S已存在
//操作结果:栈S清为空栈

Push(&S,e)

Status Push(SqStack &S,SElemType e)//入栈
{
    if(S.top - S.base == S.stacksize)//栈满
        return ERROR;
    *S.top++=e;
    return OK;
}
//初始条件:栈S已存在
//操作结果:插入元素e为新的栈顶元素

Pop(%S,&e)

Status Pop(SqStack &S,SElemType &e)//出栈
{
    if(S.top == S.base)
        return ERROR;
    e = *--S.top;
    return OK;
}
初始条件:栈S已存在且非空
//操作结果:若栈不空,删除S的栈顶元素,并用e返回其值,并返回OK;否则返回ERROR

空栈条件:base == top

栈满条件:top - base == stacksize

上溢(overflow):栈已经满,又要压入元素
下溢(underflow):栈已经空,还要弹出元素

栈中元素个数: top - base

链栈

链表的头指针是栈顶
不需要头结点
基本不存在栈满的情况
空栈相当于头指针指向空
插入和删除仅在栈顶处执行

InitStack(&S)
void InitStack(LinkStack &S)
{
    S = NULL;
    return OK;
}
//构造一个空栈,栈顶指针置为空
StackEmpty(S)
Status StackEmpty(LinkStack S)
{
    if(S == NULL)return TRUE;
    else return FALSE;
}
//判断链栈是否为空
Push(&S,e)
Status Push(LinkStack &S,SElemType e)//入栈
{
    p = new StackNode;//生成新结点p
    p->data = e;//将新结点数据域置为e
    p->next = S;//将新结点插入栈顶
    S = p;//修改栈顶指针
    return OK;
}
Pop(&S,&e)
Status Pop(LinkStack &S,SElemType &e)//出栈
{
    if(S == NULL)return ERROR;
    e = S->data;
    p = S;
    S = S->next;
    delete p;
    return OK;
}
GetTop(S)
SElemType GetTop(LinkStack S)//取栈顶元素
{
    if(S != NULL)
        return S->data;
}

队列

队列

队列是仅在 表头 \color{red}{表头} 表头进行删除、 表尾 \color{red}{表尾} 表尾进行插入操作的线性表

运算规则:
先进先出

#define MAXQSIZE 100
Typedef struct{
    QElemType *base;//初始化的动态分配存储空间
    int front;//头指针
    int rear;//尾指针
}SqQueue;
InitQueue(&Q)
Status InitQueue(SqQueue &Q)
{
    Q.base = new QElemType[MAXQSIZE];
    if(!Q.base)exit(OVERFLOW);//存储分配失败
    Q.front = Q.rear = 0;//头指针尾指针置为0,队列为空
    return OK;
}
int QueueLength(Q)
int QueueLength(SqQueue Q)
{
    return (Q.rear - Q.front + MAXQSIZE)%MAXQSIZE;
}
EnQueue(&Q,e)
Status EnQueue(SqQueue &Q, QElemType e)//循环队列入队
{
    if((Q.rear+1)%MAXQSIZE == Q.front)return ERROR;//队满
    Q.base[Q.rear] = e;//新元素加入队尾
    Q.rear = (Q.rear + 1)%MAXQSIZE;//队尾指针+1
    return OK;
}
DeQueue(&Q,&e)
Status DeQueue(SqQueue &Q, QElemType &e)//出队
{
    if(Q.front == Q.rear)return ERROR;//队空
    e = Q.base[Q.front];//保存队头元素
    Q.front = (Q.front + 1)%MAXQSIZE;//队头指针+1
    return OK;
}
GetHead(Q)
Status GetHead(SqQueue Q)
{
    if(Q.front != Q.rear)//队列不为空
        return Q.base[Q.front];//返回头指针元素的值,队头指针不变
}
链队列
#define MAXQSIZE 100
typedef struct Qnode{
    QElemType data;
    stuct Qnode *next;
}QNode,*QuenePtr;

typedef struct{
    QuenePtr front;
    QuenePtr rear;
}LinkQueue;
InitQueue(&Q)
Status InitQueue(LinkQueue &Q)
{
    Q.front = Q.rear =(QueuePtr)malloc(sizeof(QNode));
    if(!Q.front)exit(OVERFLOW);
    Q.front->next = NULL;
    return OK;
}
DestroyQueue(&Q)
Status DestroyQueue(LinkQueue &Q)
{
    while(Q.front)
    {
        p = Q.front->next;free(Q.front);Q.front = p;
    }
    return OK;
}//销毁链队列,从队头指针开始,一次释放所有节点

EnQueue(&Q,e)

Status EnQueue(LinkQueue &Q,QElemType e)
{
    p = (QueuePtr)malloc(sizeof(QNode));
    if(!p)exit(OVERFLOW);
    p->data = e; p->next = NULL;
    Q.rear->next = p;
    Q.rear = p;
    return OK;
}

DeQueue(&Q, &e)

Status DeQueue(LinkQueue &Q,QElemType &e)
{
    if(Q.front == Q.rear)return ERROR;
    p = Q.front->next;
    e = p->data;
    Q.front->next = p->next;
    if(Q.rear == p)Q.rear = Q.front;
    delete P;
    return OK;
}
GetHead(Q,&e)
Status GetHead(LinkQueue Q,QElemTyoe &e)
{
    if(Q.front == Q.rear)return ERROR;
    e = Q.front->next->data;
    return OK;
}
EnQueue(&Q, e)
Status EnQueue(LinkQueue &Q, QElemType e)
{
    p = (QueuePtr)malloc(sizeof(QNode));
    if(!p) exit(OVERFLOW);
    p->data = e; p->next = NULL;
    Q.rear->next = p;
    Q.rear = p;
    return OK;
}
DeQueue(LinkQueue &Q,QElemType &e)
Status DeQueue(LinkQueue &Q,QElemType &e)
{
    if(Q.front == Q.rear) return ERROR;
    p = Q.front->next;
    e = p->data;
    Q.front->next = p->next;
    if(Q.rear == p)Q.rear = Q.front;
    delete p;
    return OK;
}

由任意字符组成的有限序列

子串:串中任意个连续字符组成的子序列(含空串和自身)
真子串:串中任意个连续字符组成的子序列(含空串,不含自身)
子串位置:子串第一个字符在主串中的位置
空格串:由一个或多个空格组成的串,与空串不同

串相等:当且仅当两个串的长度相等且各个对应位置上的字符都相同时,这两个串才是相等的

#define MAXLEN 255
typedef struct{
    char ch[MAXLEN+1];//存储串的一维数组
    int length;//串当前长度
}SString;

Index(S,T,pos)

将主串的第pos个字符和模式串的第一个字符比较

若相等,继续诸葛比较后续字符;
若不等,从主串的下一个字符起,重新与模式串的第一个字符比较

int Index_BF(SString S, SString T, int pos){
    int i=pos, j=1;
    while(i<=S.length && j<=T.length)
    {
        if(s.ch[i]==t.ch[j]){i++;j++;}//主串和子串依次匹配下一个字符
        else {i=i-j+2; j=1;}//主串、字串指针回溯重新开始下一次匹配
    }
    if(j>=T.length)return i-T.length;//返回匹配的第一个字符下标
    else return 0;//模式匹配不成功
}

KMP算法

int Index_KMP(SString S, SString T, int pos){
    int i=pos, j=1;
    while(i<=S.length && j<=T.length)
    {
        if(j==0||S.ch[i]==T.ch[j]){ i++;j++;}
        else j=next[j];/*i不变,j后退*/
    }
    if(j>T.length) return i-T.length;
    else reurn 0;
}

void get_next(SString T, int &next[]){
    i=1;next[1]=0;j=0;
    while(i<T.length)
    {
        if(j==0 || T.ch[i] == T.ch[j]){
            i++;j++;
        	next[i] = j;
        }  
        else
            j = next[j];
    }
}

void get_nextval(SString T, int &nextval[]){
    i=1;nextval[1]=0;j=0;
    while(i<T.length){
        if(j==0 || T.ch[i] == T.ch[j]) nextval[i] = j;
        else nextval[i] = nextval[j];
    }
    else j = nextval[j];
}

串的链式存储—-块链结构

#define CHUNKSIZE 80//块的大小
typedef struct Chunk{
    char ch[CHUNKSIZE];
    struct Chunk *next;
}Chunk;

typedef struct{
    Chunk *head,*tail;//串的头指针和尾指针
    int curlen;//串的当前长度
}LString;//字符串的块链结构

数组

矩阵的压缩存储

稀疏矩阵:矩阵中非零元素很少(小于5%)

二叉树

顺序存储

#define MAXTSIZE 100
Typedef TElemType SqBiTree[MAXSTIZE]
SqBiTree bt;

链式存储

typedef struct BiNode{
	TElemType data;
    struct BiNode *lchild,*rchild;
}BiNode,*BiTree;

遍历

Status PreOrderTraverse(BiTree T){
    if(T==NULL)return OK;
    else
    {
        visit(T);//fan
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
}

层次遍历算法:

void LevelOrder(BNode *b){
    BTNode *p; SqQueue *qu;
    InitQueue(qu);//初始化队列
    enQueue(qu, b);//根结点指针进入队列
    while(!QueueEmpy(qu)){
        deQueue(qu, p);//出队结点p
        printf("%c", p->data);//访问结点p
        if(p->lchild!=NULL)enQueue(qu, p->lchild);
        if(p->rchild!=NULL)enQueue(qu,p->rchild);
    }
}

线索二叉树

如果某个结点的左孩子为空,则将空的左孩子指针域改为指向其前驱;
如果某个结点的右孩子为空,则将空的右孩子指针域改为指向其后继;

新增两个标志域ltag和rtag,bin并约定:
ltag = 0 lchild 指向该结点的左孩子
ltag = 1 lchild 指向该结点的前驱
ltag = 0 lchild 指向该结点的右孩子
ltag = 1 lchild 指向该结点的后继

typedef struct BiThrNode{
    int data;
    int ltag, rtag;
    struct BiThrNode *lchild, rchild;
}BiThrNode,*BiThrTree;

森林

是 m(m >= 0) 棵互不相交的树的集合

typedef struct PTNode{
    TElemType data;
    int parent;
}PTNode;
#define MAX_TREE_SIZE 100
typedef struct{
    PTNode nodes[MAX_TREE_SIZE];
    int r, n;//根节点位置和结点个数
}PTree

哈夫曼树

typedef struct{
    int weight;
    int parent,lch,rch;
}HTNode,*HuffmanTree;
void CreatHuffmanTree(HuffmanTree HT, int n)//构造哈夫曼树——哈夫曼算法
{
    if(n<=1)return;
    m=2*n-1;//数组共2n-1个元素
    HT = new HTNode[m+1];//0号单元未用,HT[m]表示根结点
    for(i=1;i<=m;i++)
    {
        HT[i].lch=0; 
        HT[i].rch=0;
        HT[i].parent = 0;
    }
    for(i=1;i<=n;i++)
        cin >> HT[i].weight;
}//初始化 
for(i=n+1;i<=m;i++)//合并产生n-1个结点
{
    Select(HT,i-1,s1,s2);//在HT[k](1<=k<=i-1)中选择两个其双亲域为0
    //且权值最小的结点,并返回他们在HT中的序号s1和s2
    HT[s1].parent = i;
    HT[s2].parent = i;//从F中删除s1 s2
    HT[i].lch = s1;
    HT[i].rch = s2;//s1,s2分别作为i的左右孩子
    HT[i].weight = HT[s1].weight + HT[s2].weight;//i的权值为左右孩子的权值之和
}
void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)//从叶子到根你想求每个字符的哈夫曼编码,存储在编码表HC中
{
    HC = new char *[n+1];//分配n个字符编码的头指针矢量
    cd =new char [n];//分配临时存放编码的动态数组空间
    cd[n-1] = '\0';//编码结束符
    for(i=1;i<=n;i++)
    {
        start = n-1;
        c=i;
        f=HT[i].parent;
        while(f!=0)//从叶子结点开始向上回溯,直到根结点
        {
            --start;//回溯一次start向前指一个位置
            if(HT[f].lchild == c)
                cd[start]= '0';//结点c是f的左孩子,则生成代码0
            else
                cd[start]= '1';//结点c是f的右孩子,则生成代码1
            c=f;
            f=HT[f].parent;//继续向上回溯
        }//求出第i个字符的编码
        HC[i]=new char [n-start];//为第i个字符串编码分配空间
        strcpy(HC[i], &cd[start]);//将求得的编码从临时空间cd赋值到HC的当前行中
    }
    delete cd;
}

邻接矩阵

#define Maxlnt 32767 	//表示极大值,即正无穷
#define MVNum 100 	//最大顶点数
typedef char VerTexType;	//设顶点的数据类型为字符串
typedef int ArcType; 	//设边的权值类型为整型

typedef struct{
    VerTexType vexs[MVNum]; //顶点表
    ArcType arcs[MVNum][MVNum]; //邻接矩阵
    int vexnum,arcnum; //图的当前点数和边数
}AMGraph;

创建无向网

Status CreateUDN(AMGraph &G){
    //采用邻接矩阵表示法,创建无向网G
    cin >> G.vexnum >> G.arcnum;//输入总项顶点数 总边数
    for(i = 0; i < G.vexnum; i++)
        cin >> G.vexs[i]; //依次输入点的信息
    for(i = 0; i < G.vexnum; i++) //初始化邻接矩阵
        for(j = 0; j < G.vexnum; j++)
            G.arcs[i][j] = Maxlnt; //边的权值均为极大值
    for(k = 0; k< G.arcnum; k++)//构造邻接矩阵
    {
        cin >> v1 >> v2 >>w;  //输入一条边所依附的顶点及边的权值
    i = LocateVex(G, v1); 
    j = LocateVex(G, v2); //确定v1和v2在G中的位置
    G.arcs[i][j] = w; //边<v1, v2>的权值为w
    G.arcs[j][i] = G.arcs[i][j];//置<v1, v2>的对称边<v2, v1>的权值为w
    }
    return OK;
}

查找顶点

int LocateVe(AMGraph G, VertexType u){
    //在图中查找顶点u在顶点表中的下标
    int i;
    for(i = 0; i < G.vexnum; i++)
        if(u == G.vexs[i]) return i;
    return -1;
}

邻 接表

typedef struct VNode{
    VerTexType data; //顶点信息
    ArcNode *firstarc;//指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum];//AdjList表示邻接表类型
#define MVNum 100 //最大顶点数
typedef struct ArcNode{  //边结点
    int adjvex;		//该边所指向的顶点的位置
    struct ArcNode * nextarc;//指向下一条边的指针
    Otherlnfo info;//和边相关的信息
}ArcNode;
typedef struct{
    AdjList vertices;//vertices--vertex的复数
    int vexnum,arcnum;
}ALGraph;

创建无向网

Status CreateUDG(ALGraph &G){	//采用邻接表表示法,创建无向图G
    cin> >G.vexnum> >G.arcnum;	//输入总顶点数,总边数
	for(i = O; i<G.vexnum; ++i){	//输入各点,构造表头结点表
		cin>> G.vertices[i].data;	//输入顶点值
	G.vertices[i].firstarc=NULL;	//初始化表头结点的指针域}//for
	for(k = O; k<G.arcnum;++k){	//输入各边,构造邻接表
		cin>>v1> >v2;	//输入一条边依附的两个顶点
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
        p1=new ArcNode;	//生成一个新的边结点*p1
	p1->adjvex=j;	//邻接点序号为j
	p1->nextarc= G.vertices[i].firstarc;
	G.vertices[i].firstarc=p1;//将新结点*p1插入顶点vi的边表头部
	p2=new ArcNode;
	p2->adjvex=i;	//邻接点序号为i
	p2->nextarc= G.vertices[j].firstarc;
	G.vertices[j].firstarc=p2;//将新结点*p2插入顶点vj的边表头部
    }//for
    return OK;

十字链表

在这里插入图片描述

邻接多重表

在这里插入图片描述

图的遍历

深度优先遍历

在访问图中某一起始顶点v后,由v出发,访问它的任一邻接顶点w;
再从W出发,访问与w邻接但还未被访问过的顶点W2;
然后再从W2出发,进行类似的访问,…
如此进行下去,直至到达所有的邻接顶点都被访问过的顶点u为止。接着,退回一步,退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。
如果有,则访可此顶点,之口再从此顶点出发,进行与前述类似的访问;
如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止。

void DFS(AMGraph G, int v)//图G为邻接矩阵类型
{
    cout << v; visited[v] = true;//访问第v个顶点
    for(w = 0;w < G.vexnum; w++)//依次检查邻接矩阵v所在的行
        if((G.arcs[v][w]!=0)&&(!visited[w]))
            DFS(G,w);//w是v的邻接点,如果w未访问,则递归调用DFS
}

广度优先遍历

void BFS (Graph G, intv)//按广度优先非递归遍历连通图G
{
    cout<sv; visited[v] =true;//访问第v个顶点
	lnitQueue(Q);//辅助队列Q初始化,置空
	EnQueue(Q, v);//v进队
	while(!QueueEmpty(Q)){//队列非空
        DeQueue(Q, u);//队头元素出队并置为u
	for(w = FirstAdjVex(G,u); w> =O; w = NextAdjVex(G, u, w))
        if(!visited[w])//w为u的尚未访问的邻接顶点
        {
		cout<<w; visited[w] = true; EnQueue(Q, w);//w进队
        }//if
}//while
}//BFS

Prim(普里姆)算法

算法思想:

设N=(V,E)是连通网,TE是N上最小生成树中边的集合。
初始令U={u0},(uo ∈ V),TE={ }。
在所有u∈U, v∈ V-U的边(u, v)∈E中,找一条代价最小的边(uo,vo)。
将(uo,vo)并入集合TE,同时vo并入U
重复上述操作直至U=V为止,则T=(V,TE)为N的最小生成树。

时间复杂度:O(n^2)

克鲁斯卡算法

算法思想:

设连通网N = (V,E),令最小生成树初始状态为只有n个顶点而无边的非连通图T=(V.{ }),每个顶点自成一个连通分量。
在E中选取代价最小的边,若该边依附的顶点落在T中不同的连通分量上(即:不能形成环),则将此边加入到T中;否则,舍去此边,选取下一条代价最小的边。
依此类推,直至T中所有顶点都在同一连通分量上为止。

时间复杂度:O(eloge)(e为边数)

Dijistra算法

T中顶点对应的距离值用辅助数组D存放。
D[i]初值:若<Vo, Vi>存在,则为其权值;否则为∞。
从T中选取一个其距离值最小的顶点Vj,加入S。
对T中顶点的距离值进行修改:若加进Vj作中间顶点,从Vo到Vi的距离值比不加Vj的路径要短,则修改此距离值。
重复上述步骤,直到S=V为止。

查找

typedef struct{
    KeyType key;//关键字域
    ....  		//其他域
}ElemType;

typedef struct {//顺序表结构类型定义
    ElemType *R;//表基址
    int length;//表长
}SSTable;
SSTable ST;

int Search_Seq(SSTable ST, KeyType key){
    //若成功返回其位置信息,否则返回0
    for(i=ST.length;i>=1;i--)
        if(ST.R[i].key == key) return i;
    return 0;
}

二分查找

int Search_Bin ( SSTable ST,KeyType key ) {
    low = 1 ; high = ST.length ;//置区间初值
    while (low <= high) 
    {
        mid = (low + high)/ 2;
        if (ST.R[mid].key == key)return mid ;//找到待查元素
        else if (key <ST.R[mid].key)//缩小查找区间
			high=mid-1;//继续在前半区间进行查找
        else low = mid + 1;//继续在后半区间进行查找
    }
return 0;//顺序表中不存在待查元素
} //Search_Bin

效率:O(log2 n)

二叉排序树

typedef struct{
    KeyType key;//关键字项
    InfoType otherinfo;//其他数据域
}ElemType;

typedef struct BSTNode{
    ElemType data; //数据域
    struct BSTNode *lchild, *rchild; //左右孩子指针域
}BSTNode, *BSTree;

BSTree T;//定义二叉排序树T

BSTree SearchBST(BSTree T,KeyType key){
    if((!T)||key == T->data.key)return T;
    else if(key < T->data.key)
        return SearchBST(T->lchild,key);//在左子树中继续查找
    else return SearchBST(T->rchild,key);//在右子树中继续查找
}//
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值