数据结构与算法笔记

文章目录


程序的本质 = 数据结构 + 算法

第一章 数据结构

1.1 数据结构的定义

数据结构( Data Structure) 是数据的组织方式。程序中用到的数据都不是孤立的,而是有相互联系的,根据访问数据的需求不同,同样的数据可以有多种不同的组织方式。
以前学过的复合类型也可以看作数据的组织方式,把同一类型的数据组织成数组, 或者把描述同一对象的各成员组织成结构体。数据的组织方式包含了存储方式访问方式这两层意思,二者是紧密联系的。
例如,数组的各元素是一个挨一个存储的,并且每个元素的大小相同,因此数组可以提供按下标访问的方式,结构体的各成员也是一个挨一个存储的,但是每个成员的大小不同,所以只能用运算符加成员名来访问,而不能按下标访问。
一般来说,在处理数据时,什么样的数据结构,就会影响我们采用什么样的算法来处理数据。

1.2 数据结构的逻辑分类与物理存储

1.2.1 线性的物理储存

已经说过很多遍啦,我们的内存空间是线性的:
在这里插入图片描述

1.2.2 逻辑分类

我们平时所说的线性,非线性,其实就是逻辑上的分类。物理上有可能不是线性的。

1.2.2.1 线性

数据原本就是线性的,数组,链表。数组在物理内存上也是一个一个连续储存,也是线性的。

1.2.2.2 非线性

数据结构本身如果是链式的,这时候在储存上往往也是链式的,也就是非线性。比如树和图。

第二章 链表 (List)

2.1 现实意义

不管是堆上,亦或是栈上,我们去申请大容量的连续内存的时候,即使是有空闲内存,由于内存碎片,往往也很容易申请失败(尤其是堆上)。链式结构的出现容许我们使用一连串不连续的内存空间来储存数据。

2.3 ADT

ADT(Abstract Data Type) ,即抽象数据类型,是一种从学术研究层面抽象的方法结果集, 表示形式。了解了解就好,没有太多实际上的用处。
在这里插入图片描述

2.4 实现

2.4.1 单向链表

#include "MyList.h"
#include <iostream>

using namespace std;

NodeList* CreateLIst()
{
   
    //创建头节点,申请空间;
    NodeList* head = (NodeList*)malloc(sizeof(NodeList));
    if (head == nullptr)
    {
   
        cout << "Malloc Erro" << endl;
        exit(-1);
    }

    head->data = 0;
    head->next = nullptr;
    return head;
}


void InsertList(NodeList* head, int newData)
{
   
    NodeList* cur = (NodeList*)malloc(sizeof(NodeList));
    cur->data = newData;
    cur->next = head->next;//让新来的节点有所指向;
    head->next = cur;
}


void TravereList(NodeList* head)
{
   
    head = head->next;
    if (!head)
    {
   
        cout << "链表未生成";
    }
    while (head)
    {
   
        cout << head->data << " ";
        head = head->next;
    }
    cout << endl;
}


int LenList(NodeList* head)
{
   
    int length = 0;
    head = head->next;
    for (head; head; length++, head = head->next);
    /*while (head)
    {
        length++;
        head = head->next;
    }*/
    return length;
}


NodeList* SearchList(NodeList* head, int find)
{
   
    head = head->next;
    while(head)
    {
   
        if(head->data == find)
            break;
        head = head->next;
    }
    return head;
}


void DeleteList(NodeList* head, NodeList* pFind)
{
   
    if (pFind->next == nullptr)
    {
   
        while (head->next!=pFind)
            head = head->next;
        
        head->next = pFind->next;
        pFind->next = nullptr;
        free(pFind);
    }
    else
    {
   
        pFind->data = pFind->next->data;
        NodeList* temp = pFind->next;
        pFind->next = temp->next;
        free(temp);
    }


    /*while (head->next!=pFind)
    {
        head = head->next;
    }
    head->next = pFind->next;
    pFind->next = nullptr;
    free(pFind);*/
}


void PopSortList(NodeList* head)
{
   
    /*NodeList* p, * q;
    int len = LenList(head);
    for (int i = 0; i < len - 1; i++)
    {
        p = head->next;
        q = p->next;
        for (int j = 0; j < len - 1 - i; j++)
        {
            if (p->data > q->data)
            {
                p->data ^= q->data;
                q->data ^= p->data;
                p->data ^= q->data;
            }
            p = p->next;
            q = q->next;
        }
    }*/

    NodeList* p, * q, * pre;
    int len = LenList(head);
    for (int i = 0; i < len - 1; i++)
    {
   
        pre = head;
        p = head->next;
        q = p->next;
        for (int j = 0; j < len - 1 - i; j++)
        {
   
            if (p->data > q->data)
            {
   
                pre->next = q;
                p->next = q->next;
                q->next = p;

                q = p->next;
                pre = pre->next;
                continue;
            }
            pre = pre->next;
            p = p->next;
            q = q->next;
        }
        
    }
}

void ReverseList(NodeList* head)
{
   
    NodeList* newHead = head->next;
    head->next = nullptr;

    NodeList* tmp = nullptr;
    while (newHead)
    {
   
        tmp= newHead->next;
        newHead->next = head->next;
        head->next = newHead;
        newHead = tmp;
    }
}


void DestoryList(NodeList* head)
{
   
    NodeList* cur;
    while (head)
    {
   
        cur = head->next;
        free(head);
        head = cur;
    }
}

2.4.2 双向链表

2.5 应用

2.5.1 逆序一个链表

2.5.2 如何判断一个链表是否有环

套圈原理。

2.5.3 求链表的中间节点,要求只用一重循环

2.5.4 约瑟夫环

第三章 栈 (Stack)

3.1 现实意义

递归的问题,本质就是函数压栈。如果利用栈工具,递归的操作,就可以完全用循环加栈的组合方式来实现。

3.2 基本概念

在这里插入图片描述

3.3 ADT

在这里插入图片描述

3.4 实现

3.4.1 线式储存实现

3.4.1.1 MyStack.h
typedef struct _MyStack {
   

    int top;
    int _length;
    char* _space;

}MyStack;

void InitStack(MyStack* p,int size)
{
   
    p->top = 0;
    p->_length = size;
    p->_space = (char*)malloc(sizeof(char) * p->_length);
}

bool IfStackFull(MyStack* p)
{
   
    return p->top == p->_length;
}

bool IfStackEmpty(MyStack* p)
{
   
    return p->top == 0;
}

void Push(MyStack* p, char ch)
{
   
    p->_space[p->top++] = ch;
}

char Pop(MyStack* p)
{
   
    return p->_space[--p->top];
}

void ResetStack(MyStack* p)
{
   
    p->top = 0;
}

void CleanStack(MyStack* p)
{
   
    free(p->_space);
}

3.4.2 链式储存实现

设计时选择表头作为栈顶指针,而不是表尾(单向链表(不含头节点))。不同于线式存储,不需要作判满操作。

typedef struct _Node {
   

    char data;
    struct _Node* next;

}Node;

typedef struct _ListStack {
   

    Node* top;

}ListStack;


void InitListStack(ListStack* p)
{
   
    p->top = (Node*)malloc(sizeof(Node));
    p->top->next = nullptr;
}

bool IsListStackEmpty(ListStack* p)
{
   
    return p->top->next == nullptr;
}

void ListStackPush(ListStack* p, char ch)
{
   
    Node * cur = (Node*)malloc(sizeof(Node));
    cur->data = ch;
    cur->next = p->top->next;
    p->top->next = cur;
}

char ListStackPop(ListStack* p)
{
   
    Node* cur = p->top->next;
    char ch = cur->data;

    p->top->next = cur->next;
    free(cur);

    return ch;
}

void ResetListStack(ListStack* p)
{
   
    while (!IsListStackEmpty(p))
    {
   
        ListStackPop(p);
    }
}

void ClearListStack(ListStack* p)
{
   
    ResetListStack(p);
    free(p->top);
}

链式结构大多数情况下无需判满。

3.5 应用

3.5.1 一组双栈

用一个数组表示两个堆栈,最大限度的利用空间,分别用数组的两端作为两个栈的起点,向中间扩展,两个栈中的元素总和不超过n时,两个栈不会相遇。

3.5.2 深度优先搜索 (打印地图版)

小弟:大哥,有岔路,往哪里走。
大哥:管它岔路不岔路,做个标记选一条走就完事了!不通再回来!

3.5.2.1 图示

在这里插入图片描述

#include <iostream>
#include <windows.h>
#include "Stack.h"

using namespace std;

#define MAXROW 10
#define MAXLINE 10

ListStack s;

int maze[MAXROW][MAXLINE] = {
   
    1,1,1,1,1,1,1,1,1,1,
    0,0,0,1,1,1,1,1,1,1,
    1,1,0,1,1,1,1,1,1,1,
    1,1,0,0,0,0,1,1,1,1,
    1,1,0,1,1,0,1,1,1,1,
    1,1,0,1,1,0,1,1,1,1,
    1,1,1,1,1,0,1,1,1,1,
    1,1,1,1,1,0,0,0,1,1,
    1,1,1,1,1,1,1,0,0,0,
    1,1,1,1,1,1,1,1,1,1
};

void DisplyMaze()
{
   
    for (int i = 0; i < MAXROW; i++)
    {
   
        for (int j = 0; j < MAXLINE; j++)
        {
   
            if (maze[i][j] == 1)
                printf("%2s", "*"); //墙
            else if(maze[i][j] == 2)
                printf("%2s", "#"); //走过的路径
            else 
                printf("%2s", "");//路
        } putchar(10);
    } printf("====================\n");
}

void Visit(int x, int y)
{
   
    Point p = {
    x,y };
    ListStackPush(&s,p);
}


int main(int argc, char** argv)
{
   
    Point sp{
    1,0 }, ep{
    8,9 };//起始点

    InitListStack(&s);

    ListStackPush(&s,sp);

    int flag = 1;

    while (!IsListStackEmpty(&s) && flag)
    {
   
        Point t;
        t = ListStackPop(&s);
        cout << "(" << t._x << ", " << t._y << ")" << endl;
        maze[t._x][t._y] = 2;
        system("cls");
        DisplyMaze();
        Sleep(100);

        //上
        if (t._x - 1 >= 0 && maze[t._x - 1][t._y] != 2 && maze[t._x - 1][t._y] != 1) //(判定边界;判定墙;判定是否走过)
            Visit(t._x - 1, t._y);

        //下
        if (t._x + 1 <= 9 && maze[t._x + 1][t._y] != 2 && maze[t._x + 1][t._y] != 1)
            Visit(t._x + 1, t._y);

        //左
        if (t._y - 1 >= 0 && maze[t._x][t._y-1] != 2 && maze[
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值