【数据结构郝斌】3、模块一:线性结构

1、连续存储(数组)

 int a[10];
 int *pArr = (*int

 1)什么叫数组
  元素类型相同,大小相等。
 2)数组的优缺点
  优点:存取速度快
  缺点:事先必须知道数组的长度,插入删除元素慢,空间通常是有限制,需要大块连续内存。
  练习代码见:数据结构数组算法.c
 确定一个数组需要几个信息:
  数组首地址
  数组长度
  有效位数
2、离散存储(链表)
 1)链表优缺点:
  优点:空间没有限制,插入删除元素快
  缺点:存取速度很慢。
 2)预备知识:typedef的用法:

typedef struct Student
{
    int sid;
    char name[100];
    char sex;
}*PST,ST;   //ST等价于struct Student,PST等价于:struct Student *
//给 struct Student类型的指针PST
//此时PST等价于:struct Student * 是一个指针

  树与图都是靠链表实现的,所以,链表非常重要。
 3)定义:
  n个节点离散分配
  彼此通过指针相连
  每个节点只有一个前去节点,每个节点只有一个后续节点。
  首节点没有前驱结点,尾节点没有后续节点。
  专业术语:
   首节点:
    第一个有效节点
   尾节点:
    最后一个有效节点,指向下一个元素的指针为空。
   头节点:
    头节点数据类型与首节点数据类型相同
    第一个有效节点前的节点
    不存放有效数据
    目的主要是为了方便对链表的操作。
   头指针:
    指向头结点的指针变量
   尾指针:
    指向尾节点的指针变量

  如果希望通过一个函数来对链表进行处理,我们至少徐亚接收链表的那些参数(确定一个链表需要几个参数):
   只需要一个参数:头指针
   因为我们通过头指针可以推算出链表的其他所有信息。
  链表的定义:

typedef struct Node
{
    int data;               //数据域

    struct Node *pNext; //指针
}NODE,*PNODE;           //NODE等价于struct Node, PNODE等价于struct Node *

 4)分类:
  单链表:
  双链表:
   每个节点有两个指针域,指向前一个与后一个节点。
  循环链表:
   能通过任何一个节点找到其他所有的节点。
  非循环链表:
 5)算法:
  遍历
  查找
  清空
  销毁
  求长度
  排序
  删除节点:

这里写图片描述

p->pNext = p->pNext->pNext; //内存泄漏(p后边节点的内存没释放)

不能free(p->pNext);
正确做法:
r = p->pNext;           //r指向p后面的那个节点
p->pNext = r->pNext;
free(p->->pNext);

  插入节点:
   将新的节点q插入链表中p的后边:

这里写图片描述

r = p->pNext;  p->pNext = q;   q->pNext = r ;
或:q->pNext = p->pNext; p->pNext = q;

  算法:
   狭义的算法与数据存储方式密切相关
   广义的算法与数据存储方式无关
   泛型:
    利用某种技术达到的效果就是:不同的存储方式,执行的操作时一样的。
   学算法,最重要的不是自己编算法,重要的是看懂已有的算法。重要的是看懂答案。

3、线性结构的两种常见结构一:栈
 定义
  一种可以实现“先进后出”的存储结构
  栈类似于箱子,
 分类
  静态栈
  动态栈(用的较多)
 算法
  出栈
  压栈
  每次压栈都压入栈顶
 应用
  函数调用
  中断
  表达式求职
  内存分配
  缓冲处理
  迷宫

4、线性结构的两种常见结构二:队列

5、专题:递归
 1)1+2+3+4….100的和(递归与循环的转换)
 2)求阶乘
 3)汉诺塔
 4)走迷宫

6、相关代码:
 1//链表操作代码
 2//数据存储位置相关代码
 3//栈操作相关代码

//链表操作代码
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

struct Node
{
    int data;               //数据与
    struct Node *pNext;     //指针域
}NODE ,*PNODE;      //NODE 等价于struct Node  PNODE等价于struct Node*

//函数声明
PNODE create_list(void);            //创建链表
void traverse_list(PNODE pHead);    //遍历链表
bool is_empty(PNODE pHead);         //判断链表为空
int length_list(PNODE);             //判断链表长度
bool insert_list(PNODE,int,int);    //插入    
//在pHead所指向链表的第pos个节点的前面插入一个新的节点,该节点的值是val,并且pos的值从1开始。
bool delete_list(PNODE,int,int *);  //删除
void sort_list(PNODE);              //排序

int main(void)
{
    PNODE pHead = NULL;     //等价于struct Node* pHead = NULL;

    pHead = create_list()       //创建一个非循环单链表,并将该链表的头结点的地址赋给pHead
    traverse_list(pHead);       //遍历链表

    //输出链表长度
    int len = length_list(pHead);
    printf("链表长度是%d",len);

    //判断链表是否为空
    if(is_empty(PNODE))
        printf("链表为空");
    else 
        printf("链表不为空");

    sort_list(pHead);           //排序
    traverse_list(pHead);       //遍历链表

    return 0;
}

PNODE create_list(void)
{
    int len,i,val;

    //分配了一个不存放有效数据的头节点
    PNODE pHead =  (PNODE)malloc(sizeof(NODE));
    if(NULL == pHead)
    {
        printf("分配失败");
        exit(-1);
    }

    //定义一个指向尾节点的指针
    PNODE pTail = pHead;
    pTail->pNext = NULL;

    printf("输入要生成链表节点的个数 : len = ");
    scanf("%d",%len);

    for(i=0;i<len;i++)
    {
        printf("请输入第%d个节点的值:",i+1);
        scanf("%d",&val);

        PNODE pNew = (PNODE)malloc(sizeof(NODE));
        if(NULL == pNew)
        {
            printf("分配失败");
            exit(-1);
        }
        pNew->data = val;
        pTail->pNext = pNew;
        pNew->pNext = NULL;
        pTail = pNew;
    }
    return pHead;
}

void traverse_list(PNODE pHead)
{
    PNODE p = pHead->pNext;

    while(NULL!=p)
    {
        printf("%d ",p->data);
        p = p->pNext;
    }
    printf("\n");

    return;
}

bool is_empty(PNODE pHead)
{
    if(NULL == pHead->pNext)
        return true;
    else
        return false;
}

int length_list(PNODE pHead)
{
    PNODE p = pHead->pNext;
    int cnt;

    while(NULL!=p)
    {
        cnt ++;
        p= p->pNext;
    }
    return cnt;
}

void sort_list(PNODE pHead)
{
    int i, j, t;
    PNODE p,q;

    int len = length_list(pHead);

    for(i=0,p = pHead->pNext;i<len-1;++i,p = p->pNext)
    {
        for(j=i+1,q = p->pNext;j<len;++j,q = q->pNext)
        {
            if(p->data > q->pNext)
            {
                t = p->data;        //类似于t=a[i];
                p->data = q->data;  //类似于a[i]=a[j];
                q->data = t;        //类似于a[j]=t;
            }
        }
    }

}

//在pHead所指向链表的第pos个节点的前面插入一个新的节点,该节点的值是val,并且pos的值从1开始。
bool insert_list(PNODE pHead,int pos,int val)       //插入
{
    int i=0;
    PNODE p = pHead;

    while(NULL !=p && i<pos-1)
    {
        p=p->pNext;
        ++i;
    }//指针p指向第pos个或最后一个节点。

    if(i>pos-1 || NULL = p)//pos小于1或pos大于链表长度
        return false;


    PNODE pNew = (PNODE)malloc(sizeof(NODE));
    if(NULL== pNew)
    {
        printf("动态分配内存失败!");
        exit(-1);
    }
    pNew->data = val;

    //  pNew插入链表中
    PNODE q = p->pNext;
    p->pNext = pNew;
    pNew->pNext = q;

    retuen true;    
}

bool delete_list(PNODE pHead,int pos,int *pVal) //删除
{
    int i=0;
    PNODE p = pHead;

    while(NULL !=p->pNext&& i<pos-1)
    {
        p=p->pNext;
        ++i;
    }//指针p指向第pos-1个或最后一个节点。

    if(i>pos-1 || NULL = p->pNext)//pos小于1或pos大于链表长度
        return false;

    PNODE q = p->pNext;
    *pVal = q->data;

    //删除p节点后边的节点
    p->pNext = p->pNext->pNext;
    free(q);
    q = NULL;


    retuen true;    
}
//数据存储位置相关代码

#include<stdio.h>
#include<malloc.h>

void f(int k)
{
    int m;
    double *q = (doble *)malloc(200);
}

int main(void)
{
    int i = 10;     
    int *p = (int *)malloc(100);

    return 0;
}
//代码中 i、p、m、q,在栈里分配
//malloc开辟的100个,200个内存在堆里分配

//栈里的内存程序自动分配,动态内存需要程序员手动分配
//栈操作相关代码
/*
    创建
    压栈
    出栈
    遍历
    清空
*/

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>

typedef struct Node
{
    intdata;
    struct Node *pNext;
}NODE, * PNODE;

struct Stack
{
    PNODE pTop;     //指向栈顶      
    PNODE pBottom;  //指向栈底
}STACK,* PSTACK;


void init(PSTACK);
void push(PSTACK pS,int val);
void traverse(PSTACK);
bool pop(PSTACK,int *);             //出栈
void clear(PSTACK pS);       //框架还在,里边的元素都没了

int main(void)
{
    STACK S;
    int val;

    init(&S);                   //  初始化
    push(&S,1);                 //压栈,不能指定位置,只能压栈到栈底
    push(&S,2);                 //压栈
    traverse(&S);               //遍历输出

    clear(&S);                  //清空
    traverse(&S);               //遍历输出

    if(pop(&S,&val))                //出栈
    {
        printf("出栈成功,出栈元素是%d\n",val);
    }
    else
    {
        printf("出栈失败");
    }

    return 0;
}

void init(PSTACK pS)
{
    pS->pTop = (PNODE)malloc(sizeof(NODE)); //栈顶,头结点(无数据节点)
    if(NULL == pS->pTop)
    {
            printf("分配失败");
    }
    else
    {
        pS->pBottom = pS->pTop;
        pS->pTop->pNext = NULL;     //pS->Bottom->pNext = NULL
    }
}
void push(PSTACK pS,int val)
{
    PNODE pNew = (PNODE)malloc(sizeof(NODE));
    pNew->data = val;
    pNew->pNext = pS->pTop;         //新节点插入到原栈顶上方
    pS->pTop = pNew;                //新节点成为栈顶

    return;
}

void traverse(PSTACK pS)
{
    PNODE p = pS->pTop;

    while(p != pS->pBottom)
        {
        printf("%d  ",p->data);
        p=p->pNext;
        }
    printf("\n");
    retrun ;
}

bool empty(PSTACK pS)
{
    if(pS->pTop == pS->pBottom)
        return true;
    else
        return false;
}

//把pS所指向的栈出栈一次,并把出战的元素存入pVal形参所指向的变量中,
bool pop(PSTACK pS,int *pval)               //出栈
{
    if(empty(pS))
    {
        return false;
    }
    else
    {
        PNODE r = pS->pTop;
        *pval = r->data;
        pS->pTop = r->pNext;
        free(r);
        r = NULL;

        return true;
    }
}

void clear(PSTACK pS)       //框架还在,里边的元素都没了
{
    if(empty(pS))
    {
        return ;
    }
    else
    {
        PNODE p = pS->pTop;
        PNODE q = p->pNext;

        while(p!=pS->pBottom)
        {
            q=p->pNext;
            free(p);
            p = q;
        }
        pS->pTop = pS->pTop;
    }

/*自己写的代码
    PNODE r;

    while(NULL != pS->pTop )
    {
        r = pS->pTop;
        pS->pTop = r->pNext;
        free(r);
    }
*/
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值