数据结构学习日记二:线性结构

二、线性表

1、线性表的顺序存储实现

#define MAXSIZE 10

typedef int ElementType;
typedef struct LNode* List;

struct LNode{
    ElementType Data[MAXSIZE];
    int Last;//最后一位数据的下标索引
};

//初始化
List MakeEmpty(){
    List PtrL;
    PtrL = (List)malloc(sizeof(struct LNode));
    PtrL->Last = -1;
    return PtrL;
}

//查找
int Find(ElementType x, List PtrL){
    int i = 0;
    while(i <= PtrL->Last && PtrL->Data[i] != x)
        i++;
    if(i > PtrL->Last) return -1;	//没有找到返回-1
    else return i;	//找到返回下标
}

//插入(这里的i是从1开始的)(实际是Data[i-1]插入x)
void Insert(ElementType x, int i, List PtrL){
    int j;
    if(PtrL->Last == MAXSIZE-1){//表空间满了,无法插入
        printf("表满");
        return;
    }
    if(i < 1 || i > PtrL->Last+2){
        printf("位置不合法");
        return;
    }
    for(j = PtrL->Last; j >= i-1; j--)//原数组的a[i-1]..a[last]后移1位
        PtrL->Data[j+1] = PtrL->Data[j];
    PtrL->Data[i-1] = x;	//插入x
    PtrL->Last++;			//更新长度
    return;
}

//删除(i从1开始)(想要删除的元素,可以在此基础上改)
void Delete(int i, List PtrL){
    int j;
    if(i < 1 || PtrL->Last+1){
        printf("删除位置非法");
        return;
    }
    for(j = i; j <= PtrL->Last; j++)//a[i]..a[last]前移
        PtrL->Data[j-1] = PtrL->Data[j];
    PtrL->Last--;	//更新长度
    return;
}

2、线性表的链式存储实现

typedef int ElementType;
typedef struct LNode* List;

struct LNode{
    ElementType Data;
    List Next;
};

//求表长
int Length(List PtrL){
    List p = PtrL;
    int j = 0;
    while(p){
        p = p->Next;
        j++;
    }
    return j;
}

//按序号查找
List FindKth(int k, List PtrL){
    List p = PtrL;
    int i = 1;
    while(p != NULL && i < k){
        p = p -> Next;
        i++;
    }
    if(i == k) return p;//找到,返回结点指针
    else return NULL;	//否则返回空
}
//按值查找
List Find(ElementType x, List PtrL){
    List p = PtrL;
    while(p != NULL && p->Data != x)
        p = p->Next;
    return p;
}

//插入
List Insert(ElementType x, int i, List PtrL){
    List p, s;
    if(i == 1){	//新结点在表头插入
        s = (List)malloc(sizeof(struct LNode));
        s->Data = x;
        s->Next = PtrL;
        return s;
    }
    p = FindKth(i-1, PtrL);	//查找第i-1个结点
    if(p == NULL){	//第i-1个结点不存在,不能插入
        printf("插入位置错误");
        return NULL;
    } else{
        s = (List)malloc(sizeof(struct LNode));
        s->Data = x;
        s->Next = p->Next;
        p->Next = s;
        return PtrL;
    }
}

//删除
List Delete(int i, List PtrL){
    List p, s;
    if(i == 1){	//删除首结点
        s = PtrL;
        if(PtrL != NULL) PtrL = PtrL->Next;//修改指向
        else return NULL;
        free(s);	//清空首结点的空间
        return PtrL;
    }
    p = FindKth(i-1, PtrL);	//查找i-1结点
    if(p == NULL){
        printf("结点不存在");
        return NULL;
    } else if(p->Next == NULL){
        printf("想要删除的结点不存在");
        return NULL;
    } else {
        s = p->Next;	//s指向i结点
        p=Next = s->Next;	//从链表中摘除
        free(s);	//释放被删除结点
        return PtrL;
    }
}

3、广义表结构

引入:

假设有个二元多项式:P(x,y) = 9x12y2 + 4x12 + 15x8y3 - x8y + 3x2

然后可以看成以x为变量的一元多项式:

​ P(x,y) = (9y2 + 4)x12 + (15y3 - y)x8 + 3x2

接着就可以统一成图中的结点结构,在普通线性表的基础上,用 tag 区分是常数系数,还是多项式。然后 union 把这两种统一起来。

结构图:

广义表结点结构

typedef int ElementType;
typedef struct GNode* GList;
struct GNode{
    int Tag;	//标志:0表示结点是单元素,1表示结点是广义表
    union {		//联合体,单元素Data 和子表指针SubList 共用空间
        ElementType Data;
        GList SubList;
    }URegion;
    GList Next;	//指向后继节点
}

4、多重链表

链表中的结点可能同时隶属多个链。

4.1 稀疏矩阵(十字链表)

只存储矩阵中的非0项:结点数据包含(row, col, Value)

同时结点有两个指针:行指针Right, 列指针 Down。
稀疏矩阵(十字链表)

蓝色框里的是稀疏矩阵入口,记录的数据是行数、列数、非零项个数。

然后总共有两种结点,一种Head头结点,一种Term存数据的,都能down和Right。

两种结点很像,所以可以使用union来设计。

  • 用一个标志 tag 来区分头结点和数据结点;
  • 头结点的标识值为”Head“,非0元素结点的标识值为“Term”。

稀疏矩阵结点结构图

三、栈

1、栈的顺序存储实现

#define MAXSIZE 100
typedef int ElementType;
typedef struct SNode* Stack;

struct SNode{
    ElementType Data[MAXSIZE];
    int Top;
};

//入栈
void Push(Stack PtrS, ElementType item){
    if(PtrS->Top == MAXSIZE-1){
        printf("栈满"); return;
    } else{
        PtrS->Data[++(PtrS->Top)] = item;
        return;
    }
}

//出栈
ElementType Pop(Stack PtrS){
    if(PtrS->Top == -1){
        printf("栈空");
        return ERROR;	//ERROR是ElementType的错误值
    } else
        return (PtrS->Data[(PtrS->Top)--]);
}

2、栈的链式存储实现

typedef int ElementType;
typedef struct SNode* Stack;
struct SNode{
    ElementType Data;
    struct SNode* Next;
};

//初始化头结点
Stack CreateStack(){
    Stack S;
    S = (Stack)malloc(sizeof(struct SNode));
    S->Next = NULL;
    return S;
}

//判断是否为空
int IsEmpty(Stack S){
    return (S->Next == NULL);
}

//入栈(头插法)
void Push(ElementType item, Stack S){
    struct SNode* newNode;
    newNode = (struct SNode*)malloc(sizeof(struct SNode));
    newNode->Data = item;
    newNode->Next = S->Next;
    S->Next = newNode;
}

//出栈
ElementType Pop(Stack S){
    struct SNode* FirstNode;
    ElementType TopElem;
    if(IsEmpty(S)){
        printf("栈空");
        return NULL;
    } else{
        FirstNode = S->Next;
        S->Next = FirstNode->Next;
        TopElem = FirstNode->Data;
        free(FirstNode);
        return TopElem;
    }
}

3、栈的应用:表达式求值

3.1 中缀表达式转换成后缀表达式

a * ( b + c ) / d 转换成后缀表达式为: a b c + * d /

  • 碰到数字就输出
  • 碰到运算符就比较优先级,高压栈,低出栈。如果是右括号,一直出栈,直到左括号出栈。

3.2 求后缀表达式

直接从左到右扫描,遇到运算符,弹两个数出来,结果重新压栈。

3.3 栈的其他应用

  • 函数调用及递归实现
  • 深度优先搜索
  • 回溯算法
  • 。。。

四、队列

1、队列的顺序存储实现

循环队列。空一格。入队处理rear,出队修改front。

#define MAXSIZE 100
typedef int ElementType;
struct QNode{
    ElementType Data[MAXSIZE];
    int rear;
    int front;
};
typedef struct QNode* Queue;

//入队
void AddQ(Queue PtrQ, ElementType item){
    if((PtrQ->rear+1) % MAXSIZE == PtrQ->front){
        printf("队列满");
        return;
    }
    PtrQ->rear = (PtrQ->rear+1) % MAXSIZE;
    PtrQ->Data[PtrQ->rear] = item;
}

//出队
ElementType DeleteQ(Queue PtrQ){
    if(PtrQ->front == PtrQ->rear){
        printf("队列空");
        return ERROR;
    } else {
        PtrQ->front = (PtrQ->front+1) % MAXSIZE;
        return PtrQ->Data[PtrQ->front];
    }
}

2、队列的链式存储实现

typedef int ElementType;

struct Node{	//链表
    ElementType Data;
    struct Node* Next;
};
struct QNode{	//队列结构
    struct Node* rear;//队尾结点
    struct Node* front;//队头结点
};
typedef struct QNode* Queue;

//不带头结点的出队
ElementType DeleteQ(Queue PtrQ){
    struct Node* FrontNode;
    ElementType FrontElem;
    
    if(PtrQ->front == NULL){
        printf("队列为空"); return ERROR;
    }
    FrontNode = PtrQ->front;
    if(PtrQ->front == PtrQ->rear)//如果只有一个元素
        PtrQ->front = PtrQ->rear = NULL;//删除队列
    else
        PtrQ->front = PtrQ->front->Next;
    FrontElem = FrontNode->Data;
    free(FrontNode);//释放结点
    return FrontElem;
}

//入队
void AddQ(ElementType elem, Queue PtrQ){
    struct Node* newNode;//初始化新结点
    newNode->Data = elem;
    newNode->Next = NULL;
    
    if(PtrQ->front == NULL)	//队列还是空的,新增第一个结点
        PtrQ->front = PtrQ->rear = newNode;
    else
        PtrQ->rear->next = newNode;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值