第二个一千行总结-数据结构C复习--知识点总结2--五到七章

第五章 数组与广义表

n维数组看作数据元素为n-1维数组的线性表

数组地址计算:略

特殊矩阵压缩:

三角矩阵;三对角矩阵(带状矩阵);

稀疏矩阵:存储数据总量小于百分之三十

稀疏矩阵用三元组(行,列,值)储存,定义如下:
typedef struct{
    int row, col;//行,列 
    int e;
}Triple;

typedef struct{
    Triple data[MAX+1];
    int m, n, len;//行,列,数据总个数 
}TSMtrix;

普通双for循环算法
void TransMatrix(int a[m][n], b[m][n]){
    int i, j;
    
    for(i = 0; i < m; i++)
        for(j = 0; j < n; j++)
            b[j][i] = a[i][j];    

稀疏矩阵递增转置法
void TransposeTSMatrix(TSMatrix A, TSMatrix *B){
    int i, j, k;
    
    B->m = A.n; B->n = A.m; B->len = A.len;
    //多次扫描,找到A列中对应B中的行的元素,一共扫描A.n次 
    if(B->len){
        j = 1;
        for(k = 1;k <= A.n;k++)//A.n为列数
            for(i=0 ;i < A.len;i++)               
                if(A.data[i].col == k)
                {
                    B->data[j].row = A.data[i].col;
                    B->data[j].col = A.data[i].row;
                    B->data[j].e = A.data[i].e;
                    j++;
                }
            
    }

//一次快速定位转置法
void FastTransposeTSMatrix(TSMatrix A, TSMatrix *B) {
    int col, i, j ,k;
    //值得注意的是Triple定义的数组data[]保存的是存在元素(非0元素),值为零的不存 
    int num[MAXSIZE],position[MAXSIZE];
    
    B->m = A.n; B->n = A.m; B->len = A.len;
    if(B->len){
        num[] = {0};
        //循环清0也可以
        for(t = 1;t <= A.len;t++)
            num[A.data[t].col]++;//统计第col列的数据个数 
            
        position[1] = 1;
        for(col = 2;col<=A.len;col++)//根据num每一列个数得到每一个新列第一个元素的位置 
            position[col] = position[col-1]+num[col-1]; //position为第几个元素
             
        for(p = 1;p         {
            col = A.data[p].col; 
            q = position[col];//找到该列第一个元素的位置 
            B->data[q].row = A.data[p].col;
            B->data[q].col = A.data[p].row;
            B->data[q].e = A.data[p].e;
            position[col]++;
            //下一个列号为col的非零元素再B中存放位置 
        }
    }
}

十字链表 
typedef ElemType int
typedef struct OLNode
{
    int col, row;
    ElemType value;
    struct OLNode *right, *down; 
}OLNode, *OLink;

typedef struct
{
    OLink *row_head, *col_head;//注意这个是行列头指针链表的指针数组 
    int m, n, len;                //行列长度 
}CrossList;

//建立十字链表
bool CreateCrossList(CrossList *M){
    //先输入矩阵M的相关信息 
    //为指针数组分配空间并且初始化
    //输入十字链表每个节点的相关信息
    //判断是否输入正确
    //正确则进行创建结点并且插入链表
    int m, n, len;
    int col, row;
    ElemType value;
    int i;
    OLink *q,*p;
     
    
    scanf(&m, &n, &len);
    M->len = len; M->m = m; M->n = n;
    
    if(!(M->row_head = (* OLink)malloc(m * sizeof(OLink)))) return false;
    if(!(M->col_head = (* OLink)malloc(n * sizeof(OLink)))) return false;
    //以下可以直接写M->row_head[ ] = NULL;
    for(i = 0; i < m; i++)
        M->row_head[i] = NULL;
    for(i = 0;i < n; i++)
        M->col_head[i] = NULL;
    
    for(scanf(&row, &col, &value); row != -1; scanf(&row, &col, &value))
    {
        if(!(p = (OLNode *)malloc(sizeof(OLNode)))) return false;
        p->col = col;
        p->row = row;
        p->value = value;
        //先插行再插列互相不干扰
        if(M->row_head[row] == NULL) 
            M->row_head[row] = p;
        else{
            q = M->row_head[row];
            while(q->right && q->right->row < row)
                q = q->right;
            //q此时指向该行链表最后一个元素
            //类似与尾插 
            p->right = q->right;
            q->right = p;
        }
        if(M->col_head[col] == NULL)
            M->col_head[col] = p;
        else{
            q = M->col_head[col];
            while(q->down && q->down->col < col){
                q = q->down;
            }
            p->down = q->down;
            q->down = p;
        }
    }

广义表:递归定义, 可以为无限序列(线性表为有限序列).表头为第一个元素,其余为表尾.
定义:
typedef enum{
    ATOM, LIST
}Elemtag;//atom为原子结点标志,list为表结点标志

typedef struct GLNode{
    ElemTag tag;
    
    union{//以下表明二选一 
        AtomType atom;
        struct{
            struct GLNode *hp, *tp;
        }htp;
    }atom_htp;
}GLNode , *GList;
广义表操作:略


第六章: 树与二叉树!!!!!!!!!!!

定义:根,子树,结点,度,高度(深度), 分支结点, 叶子节点, 森林, 孩子.兄弟.祖先.堂兄弟.子孙.双亲结点, 前/后辈.

 树的图解表示法 
 1.树形表示法(倒置树结构)
 2.文氏图表示法
 3.广义表示形式(嵌套括号表示法)
 4.凹入表示法    
 
二叉树!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
性质:第i层至多2^(i-1)个结点; 前k层至多2^(k-1)个结点.
叶子结点为n,度数为2结点为m,则n = m + 1. 
区别:!!!满二叉树和完全二叉树
完全二叉树为:其深度下的1~n的位置序号分别与等高的满二叉树一一对应. 其深度计算log2(n)向下取整+1
                                                            //相当于python里面的floor(log2(n)) log2(7)+1= 3

存储结构:
顺序存储结构:按照结点的层序编号以此存储到数组(向量)对应位置
链式存储结构:
定义如下:
typedef DataType int
typedef struct Node{
    DataType data;
    struct Node *LChild;
    struct Node *RChild;
}BiTNode, *BiTree; 

必考点!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!二叉树的遍历!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

遍历规则:大致按照左中右,然后先/中/后序列代表着访问根的先后顺序,先序就先访问 
先序遍历:先遍历根,再左子树,再右子树.
中序遍历:先遍历左子树,再根,再右子树.
后序遍历:...

应用广泛:表达式求值-->前缀表达式为波兰表达式, 后缀表达式为逆波兰表达式,后缀表达式易于求值

递归算法:
先/中/后序遍历只是访问根结点先后顺序不一样而已

//二叉树的遍历
//先序遍历 DLR 

void PreOrder(BiTree root){
    if(root != NULL){
        Visit(root->data);
        PreOrder(root->LChild);
        PreOrder(root->RChild);
    }
}
//中序遍历 LDR 
void InOrder(BiTree root){
    if(root != NULL){
        InOrder(root->LChild);
        Visit(root->data);
        InOrder(root->RChild);
    }
}

//后序遍历 LRD
void PostOrder(BiTree root){
    if(root != NULL){
        PostOrder(root->LChild);
        PostOrder(root->RChild);
        Visit(root->data); 
    }
}

//输出二叉树中的结点
void PreOrder(BiTree root){
    if(root != NULL){
        printf(root->data);
        PreOrder(root->LChild);
        PreOrder(root->RChild);
    }
}
//输出二叉树中的叶子结点 
//先序遍历
void PreOrder(BiTree root){
    if(root!= NULL){
        if(root->LChild == NULL && root->RChild == NULL)
            printf(root->data);
        PreOrder(root->LChild);
        PreOrder(root->RChild);
    }

//统计叶子节点的数目
//法1
//设置全局变量!!!!
int LeafCount =  0;
void leaf(BiTree root)
{
    leaf(root->LChild);
    leaf(root->RChild);
    if(root->LChild ==NULL && root->RChild == NULL){
        LeafCount++;
    }
 } 
 
 //法2 分治算法 这个有点妙! 
int leaf(BiTree root)
{
    if(root == NULL)
        LeafCount = 0;
    else if(root->LChild == NULL || root->RChild == NULL){
        LeafCount++;
    } 
    else
        LeafCount = leaf(root->LChild) + leaf(root->RChild);
    return LeafCount;
 } 
 
//建立二叉树链表方式储存二叉树
//扩展先序遍历方式创建二叉树链表
原理:一棵树先序遍历得到结点的所有值;那么一堆值根据先序遍历得到树 
void CreatBiTree(BiTree *bt){
    char ch;
    ch = getchar();
    
    if(ch == '.')
        *bt = NULL;
    else{
        *bt = (BiTree) malloc(sizeof(BiNode));
        (*bt)->data = ch;
        CreateBiTree(&(*bt)->LChild) ;
        CreateBiTree(&((*bt)->RChild);
    }

//求二叉树的高度
//后序遍历, 求高度, 递归
int PostTreeDepth(BiTree bt)
{
    int hl, hr, max;
    if(bt != NULL){
        hl = PostTreeDepth(bt->LChild);
        hr = PostTreeDepth(bt->RChild);
        max = hl > hr ? hl : hr;//三元运算符 
        return max +1 ;
    }
    else
        return 0;
 } 
 
//先序遍历实现
int depth = 0;
void PreTreeDepth(BiTree bt, int h){
    if(bt != NULL){
        if(h > depth) 
            depth = h;
        PreTreeDepth(bt->LChild, h+1);
        PreTreeDepth(bt->RChild, h+1);
    }
}

!!!!!!!!!!!!!!!!!!!!!!!!!!!!二叉树的层次遍历算法!!!!!!!!!!!!!很可能大题
void LevelOrder(BiTree bt){
    BiTree Queue[MAX];            //将队列与二叉树结合, 重点!!!!
    int front, rear;
    
    if(bt == NULL) return;
    front = rear = 0;
    
    Queue[rear] = bt;//根节点入队,队尾入队哈!
    rear++;//尾指针移走
    
    //当front!=rear即队列不为空
    while(rear != front){
        printf("%d", Queue[front]);//visit(xxx);//访问刚刚出队的元素 
        if(Queue[front]->LChild){
            Queue[rear] = Queue[front]->LChild;//存在左孩子则入队 
            rear++; 
        }
        if(Queue[front]->RChild){
            Queue[rear] = Queue[front]->RChild;
            rear++; 
        }
        front++;//出队的最后操作 
    } 

//基于栈的递归消除
//中序遍历二叉树的非递归算法
void inorder(BiTree root){
    Stack s[m];
    int top = 0;
    BiTNode *p;
    
    p = root;
    
    do{
        while(p != NULL){
            if(top > m) 
                return;
                // 栈满
            top++;
            s[top] = p;
            p = p->LChild;
            //遍历左子树 
        }
        if(top != 0){//栈空为0 
            p = s[top];
            top--;
            Visit(p->data);
            p = p->RChild;
        }
        
    }while(p != NULL || top != 0);
    //当前结点存在则入栈, 然后遍历左子树
    //不在, 退栈, 访问右子树 

//法2
//中序遍历非递归算法
void Inorder(BiTree root)
{
    Stack s;
    InitStack(&s);
    BiTNode *p = root;
    
    while(p != NULL || !IsEmpty(S))
    {//栈空, p指向NULL, 结束 
        if (p){
            Push(&S, p);
            p = p->LChild;
        }
        else
        {
            Pop(&s, &p);
            Visit(p->data);
            p = p->RChild;
        }
    }
 } 
 
//后序遍历二叉树的非递归算法
void PostOrder(BiTree root){
    BiTNode *p, *q;
    Stack S;
    q = NULL;
    p = root;
    Init(&Stack);
    
    while(p != NULL || !IsEmpty(S)){
        if(p){
            Push(&S, p);
            p = p->LChild;
        } 
        else{
            GetTop(&S, &p);
            if(p->RChild == NULL || p->RChild == q){//第二个条件判断是否也已经遍历过.类似于指针跟踪技术 
                visit(p->data);
                q = p;
                Pop(&S, &p);
                p = NULL;
            }
            else
                p = p->RChild;
        }
    }

//后序遍历法2
void PostOrder(BiTree root){
    Stack st;
    BiTNode *p, *q, *r;
    p = root;
    InitStack(&st);
    bool flag;
    
    do{
        while(p != NULL){
            Push(&st, &p);
            p = p->LChild;
        }
        r = NULL;
        flag = true;
        
        while(!IsEmpty(st) && flag){
            GetTop(&st, &p);
            if(p->RChild == r){
                Visit(p->data);
                Pop(&st, &p);
                r = p;
            }
            else{
                p = p->LChild;
                flag = false;
            }
        }
        
    }while(!IsEmpty(st));
    DestroyStack(st);


线索二叉树:
原理:n个结点的二叉树有2n个链域,而只有n-1条边(离散),n+1个链空浪费 

// LChild Ltag data Rtag RChild

typedef struct Node{
    int data;
    struct Node *LChild;
    struct Node *RChild;
    
    int Rtag;//0,指示结点的右孩子,1指示结点的遍历后继 
    int Ltag;//0,指示结点的左孩子,1指示结点的遍历前驱 
}BiTNode, *BiTree;


void Inthread(BiTree root){
    if(root != NULL){
        Inthread(root->LChild);//线索化左子树 
        if(root->LChild == NULL){
            root->Ltag = 1;
            root->LChild = pre;
        }
        if(pre != NULL && pre->RChild ==NULL){
            pre->RChild = root;
            pre->Rtag = 1;
        }
        pre = root;
        Inthread(root->RChild);
    }

//在中序线索树中找结点前驱
BiTNode *InPre(BiTNode *p){
    BiTNode *q, *pre;
    if(p->Ltag == 1) 
        pre = p->LChild;
    else{
        //在p的左子树中找最右下端点
        for(q = p->LChild; q->Rtag == 0; q = q->RChild)
            ;
        pre = q; 
    }
    return pre;
}


//在中序线索树中找后继结点 
BiTNode* InNext(BiTNode *p){
    if(p->Rtag == 1){
        Next = p->RChild;
    else{
        for(q = p->RChild; q->Ltag == 0; q = q->LChild)
            ;    
        Next = q;
    }
    return Next;
    }
}

//找中序遍历线索树第一个节点
BiTNode *InFirst(BiTNode *p){
    if(!p) return NULL;
    while(p->Ltag == 0) p = p->LChild;
    return p;
}
//遍历中序线索二叉树
void TInOrder(BiTNode Bt){
    BITNode *p;
    p = InFirst(Bt);
    while(p){
        visit(p);
        p = InNext(p);
    }

遍历确定二叉树:只有先序+中序, 后序+中序可以
尝试还原: 先序 ABCDEFGHI
          中序 BCAEDGHFI
          二叉树参考:
              A
        B------------D
         -C        E----------F
                         -G------I
                           -H

树的存储结构: 

//双亲表示法 
typedef struct TNode{
    int data;
    int parent;
}TNode;

typedef struct{
    TNode tree[MAX];
    int nodenum;
}ParentTree;

//孩子兄弟表示法 重点!!! 
typedef DataNode int
typedef struct ChildNode{//孩子链表结点定义 
    int Child;
    struct ChildNode *next;
}ChildNode;

typedef struct{//顺序表结点定义 
    DataNode data;
    ChildNode *FirstChild;
}DataNode;

typedef struct{
    DataNode nodes[MAX];
    int root;
    int num;
}ChildTree;

//孩子表示法 
tepedef struct CSNode{
    int data;
    struct CSNode *FirstChild;
    struct CSNode *NextChild;
}CSNode, *CSTree; 


森林,树,二叉树:
任意树转化为二叉树:兄弟加平行线,删右侧加线端点的与双亲的连线,旋转 
森林转化二叉树:第一颗二叉树不懂,后面的二叉树的根依次作为二前一棵二叉树的右孩子 

注意:树的先根遍历-->转换后二叉树的先序遍历
     树的后根遍历-->转换后二叉树的中序遍历 
 
树的遍历算法://孩子兄弟链表实现对树的先根遍历 
void RootFirst(CSTree root){
    if(root != NULL){
        Visit(root->data);
        p = root->FirstChild;
        while(p != NULL)
        {
            RpptFirst(p);
            p = p->NextSbling;
        }
    }

void RootFirst(CST root){
    if(root != NULL){
        Visit(root->data);
        RootFirst(root->FirstChild);
        RootFirst(root->NextSibling);
    }
}

哈夫曼树:带权叶子节点构成路径长度最短的二叉树,称最优二叉树 
路径,路径长度,结点的权,带权路径长度
类型定义:
#define N 20
#define M 2 * N -1
typedef struct{
    int weight;
    int parent;
    int LChild;
    int RChild;
}HTNode, HuffmanTree[M+1];

//Create the Tree
void CrtHuffmanTree(HuffmanTree ht, int w[], int n){
    //create ht[M+1], w[]存放n个权值
    for(i = 1; i <= n; i++)
        ht[i] = {w[i], 0, 0, 0};
    //Attention, start from 1, not 0 . So the length of ht is M + 1, not M.
    for(i = n + 1; n <= M; i++)
        ht[i] = {0, 0, 0, 0};
        
    for(i = n + 1; i <= M; i++){
        select(ht,i-1, &s1, &s2);
        //从ht[1]~ht[i-1]中选择两个parent = 0且weight最小的结点, 其序号赋值给s1, s2
        ht[i].weight = ht[s1].weight + ht[s2].weight;
        ht[s1].parent = i;
        ht[s2].parent = i;
        ht[i].LChild = s1;
        ht[i].RChild = s2;
    }

//对于第三个for 循环如下
for(i = n + 1; i <= M;i++ ){
    s1 = s2 = 32767;
    Inode = rnode = -1;
    for(k = 0; k <= i -1 ;k++){
        if(ht[k].parent == -1){
            if(ht[k].weight<= s1){
                s2 = s1; rnode = Inode;
                s1 = ht[k].weight; Inode = k;
            }
            else if(ht[k].weight <= s2){
                s2 = ht[k].weight; rnode = k;
            }
        }
    }
}

//哈夫曼编码_不用管,下一个可以看看 
void encoding(HuffmanTree ht, HuffmanCode hc, int n){
    //n 为叶子结点个数
    int start = n - 1;
    char *cd;
    cd = (char *)malloc((n + 1) * sizeof(char)); //暂时存入字符编码的字符数组 
    cd[n] = '\0';
    for(i = 1; i <= n; i++){
        start = n;
        c = i;
        p = ht[i].parent;
        while(p != -1){
            start--;
            if(ht[p].LChild == c)
                cd[start] = '0';
            else
                cd[start] = '1';
            c = p;
            p = ht[p].parent;//倒着存入的思想 
        }
        hc[i] = (char *)malloc((n+1-start) * sizeof(char));
        strcpy(hc[i], &cd[start]);
        cd = {'\0'};
    }
    free(cd); 

#define LEN 100
typedef struct{
    char ch;        //存储字符 
    char code[LEN]; //存放编码 
}TCode;//每个字符都对应唯一编码,因为哈夫曼树为前缀编码 
TCode CodeBook[LEN];//编码本 

//哈夫曼编码算法_2 
void encoding1(HTNode ht[], TCode book[], int n){
    char *str = (char *)malloc((n + 1) * sizeof(char));//存放编码 
    str[n] = '\0';
    int i, j, idx, p;
    //哈夫曼树某个叶结点下标idxa,用parent找到父节点idxb 
    for(i = 0; i < n; i++){//依次求叶子结点ht[i]的编码 
        book[i].ch = ht[i].ch;
        idx = i;
        j = n;
        while(p = ht[idx].parent > 0){
            if(ht[p].LChild == idx){
                j--;
                str[j] = '0';//左孩子 
            }
            else{
                j--;
                str[j] = '1';//右孩子 
            }
            idx = p;// idx 为下一轮找双亲的孩子,因为p = ht[idx].parent; 
        }
        strcpy(book[i].code, &str[j]);
    }
}
//解码运算算法 
void decoding(HTNode ht[], char *codes, int n){
    int p = 2 * n -2;//p为表中最后一个结点的指针, (总共2n-1个结点, 0开始), ht[p]代表root
    int i, j;
    i = 0;
    while(codes[i]!= '\0'){
        while(ht[p].LChild !=-1 && ht[p].RChild != -1){
            if(codes[i] == '0')
                p = ht[p].LChild;
            else
                p = ht[p].LChild;
            i++;
        }
        printf("%c", ht[p].ch);
        p = 2 * n -2;
    } 
}

第六章总结:

存储结构:
二叉树采用顺序储存与二叉链表储存
哈夫曼树概念,了解相关实现. 
遍历必考!

//icoding例题 
假设二叉树采用二叉链表方式存储, root指向根结点,node 指向二叉树中的一个结点,
编写函数 path,计算root到 node 之间的路径,(该路径包括root结点和 node 结点)。path 函数声明如下:
bool path(BiTNode* root, BiTNode* node, Stack* s);
其中,root指向二叉树的根结点,node指向二叉树中的另一结点,s 为已经初始化好的栈,
该栈用来保存函数所计算的路径,如正确找出路径,则函数返回 true,此时root在栈底,node在栈顶;
如未找到,则函数返回 false, 二叉树的相关定义如下:
typedef int DataType;
typedef struct Node{
    DataType data;
    struct Node* left;
    struct Node* right;
}BiTNode, *BiTree;
栈的相关定义及操作如下:
#define Stack_Size 50
typedef BiTNode* ElemType;
typedef struct{
    ElemType elem[Stack_Size];
    int top;
}Stack;
void init_stack(Stack *S); // 初始化栈
bool push(Stack* S, ElemType x); //x 入栈
bool pop(Stack* S, ElemType *px); //出栈,元素保存到px所指的单元,函数返回true,栈为空时返回 false
bool top(Stack* S, ElemType *px); //获取栈顶元素,将其保存到px所指的单元,函数返回true,栈满时返回 false
bool is_empty(Stack* S);  // 栈为空时返回 true,否则返回 false


#include "bitree.h" //请不要删除,否则检查不通过
#include
#include

bool path(BiTNode* root, BiTNode* node, Stack* s)
{
    BiTNode *p, *q; 
    int i = 0;

    p = root;
    q = NULL;
    init_stack(s);

    if (p == NULL || node == NULL)
        return false;
    if (p == node) {
        push(s, p);
        return true;
    }

    while (p != NULL || !is_empty(s)) {
        while (p) {
            push(s, p);
            if (p == node)
                return true;
            p = p->left;
        }
        top(s, &p); 
        if (p->right == q || p->right == NULL) {
            q = p;
            pop(s, &p);
            p = NULL; 
        } else {
            p = p->right;
        }
    }

    return false;
}


第七章 图

概念:vertex, head, arc, tail, edge.子图,邻接点,邻接边,度,入/出度,网,路径长度,回路,连通图.... 
分类:稀疏图,完全图,稠密图

图的存储结构://重点

//邻接表 
//分为表头结点表和边表
//前者是一个指针类型的结构数组 每一个结构包括结点域和链域
//边表储存弧结点, 弧结点结构分为三个域, 第一个储存弧结点相关信息, 
//第二个一般可以储存权重, 第三个链域存表头结点的下一个邻结点的弧 

#define MAX_VERTEX_NUM 20
typedef enum{DG, DN, UDG, UDN
} GraphKind;
typedef char VertexData

typedef struct ArcNode{//弧结点 
    int adj;
    int info; 
    struct ArcNode *nextarc;//指向下一条弧的指针 
}ArcNode;

typedef struct VertexNode{//表头结点 
    VertexData data;
    ArcNode *firstarc;
}VertexNode;

typedef struct{
    VertexNode vertex[MAX_VERTEX_NUM];
    int vexnum, arcnumber;
    GraphKind kind;
}AdjList;


//邻接矩阵
#define MAX_VERTEX_NUM 20
#define IFINITY
typedef enum{DG, DN, UDG, UDN
} GraphKind;
typedef char VertexData
typedef struct ArcNode{
    int adj;
}ArcNode;
typedef struct{
    VertexData vertex[MAX_VERTEX_NUM];
    ArcNode arc[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
    int vexnum, arcnumber;
    GraphKind kind;
}AdjMatrix;

//求顶点位置函数 
int LocateVertex(AdjMatrix *G, VertexData v){
    int i = 0;
    for(; i < G->vexnum; i++){
        if(G->vertex[i] == v)
            return i; 
    }
    return -1;
}
//创建一个有向网 
int CreateDN(AdjMatrix *G){
    
    int vexnum, arcnum;
    VertexData v1, v2;
    int i, j, k, weight;
    
    scanf("%d, %d", &vexnum, &arcnum);
    for(i = 0; i< G->vexnum; i++)
        scanf("%c", &G->vertex[i]);
    for(i = 0; i < G->vexnum; i++)
        for(j = 0; j < G->vexnum; j++)
            G->arc[i][j] = IFINITY;
    for(k = 0; k < G->arcnumber; k++){
        scanf("%c, %c, %d", &v1, &v2, &weight);
        i = LocateVertex(G, v1);
        j = LocateVertex(G, v2);
        G->arc[i][j] = weight;
    }
    return OK;
}

//十字链表 
#define MAX_VERTEX_NUM 20
typedef enum{DG, DN, UDG, UDN
} GraphKind;
typedef char VertexData
typedef struct ArcNode{
    int tailvex;   //储存当前结点信息 
    int headvex;    //储存下一个结点信息 
    struct ArcNode *hlink;//入度 
    struct ArcNode *tlink;//出度, 相当于邻接表 
    int info;         //可以存权 
}ArcNode;
typedef struct VertexNode{
    VertexData data;    //顶点信息 
    ArcNode *firstin;    //入度的第一条弧//以该顶点为弧头的第一个弧顶点 
    ArcNode *firstout;  //以该顶点为弧尾的第一个弧顶点 
}VertexNode;

typedef struct{
    VertexNode vertex[MAX_VERTEX_NUM];
    int vexnum, arcnum;
    GraphKind kind;
}OrthList;

//创建十字链表算法 
void CrtOrthList(OrthList *g){
    
    int vexnum, arcnum;
    int i, j, k;
    VertexData vh, vt;
    ArcNode *p;
    
    scanf("%d, %d", &vexnum, &arcnum);
    g->vexnum = vexnum; g->arcnum = arcnum;
    
    for(i = 0; i < vexnum; i++){
        scanf("%c", &(g->vertex[i].data));
        g->vertex[i].firstin = NULL;
        g->vertex[i].firstout = NULL; 
    }
    
    for(k = 0; k < arcnum; k++){
        scanf("%c, %c", &vh, &vt);
        i = LocateVertex(g, vt);
        j = LocateVertex(g, vh);
        p = (ArcNode *)malloc(sizeof(ArcNode));
        p->tailvex = i;
        p->headvex = j;
        //类似于头插 
        p->tlink = g->vertex[i].firstout;
        g->vertex[i].firstout = p;
        p->hlink = g->vertex[j].firstin;
        g->vertex[j].firstin = p;
    }
}


//邻接多重表 
//邻接多重表与邻接表不同, 前者主要记录边的信息
//该表有标志域, 记录是否被搜索过, 两个顶点, 分别与两个顶点关联的边 
#define MAX_VERTEX_NUM 20
typedef enum{DG, DN, UDG, UDN
} GraphKind;
typedef char VertexData
typedef struct EdgeNode{
    int mark;
    int ivex, jvex;
    struct EdgeNode *ilink;
    struct EdgeNode *jlink;//用于指向下一条依附于顶点jvex的边 //顶点的邻接边 
}EdgeNode;
typedef struct{
    VertexData data;
    EdgeNode *firstedge; 
}VertexNode;
typedef struct{
    VertexNode vertex[MAX_VERTEX_NODE];
    int arcnum, vexnum;
    GraphKind kind;
}AdjMulList;


总结: 
//邻接矩阵:二维数组, 一维数组组成, 邻接矩阵存是否两个顶点之间有边 
//邻接表:顶点指针结构数组, 弧结点构成以顶点为头结点的链表 , 节省稀疏图对邻接矩阵造成的的空间浪费 
//邻接多重表:标志域, 两个结点域, 两个链域分别对应域两个顶点的邻接边信息 
//十字链表: 邻接表和逆邻接表的结合, 每一个结点有两个链域存出度和入度信息, 两个数据域存结点信息 
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风起风里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值