数据结构与算法---浅谈数据结构

前言

毕业也没多久的我,发现大学好多东西都遗忘了或者没学好。自己打算从数据结构与算法开始,一点一滴在简书记录我的算法学习和巩固的历程。同时,希望能边和大家分享学习经历的同时,希望能够得到大家的多多指教~

数据结构与算法这一系列我的重点是在算法这一部分,数据结构的概念和基础在本节会解释一下,后期会不断的实验和更新一些基础经典和有趣的算法。其中使用的编程语言主要是C语言。

数据结构与算法概要

重新浏览了一遍书,如果让我来说数据结构与算法的一些印象。我清楚的记得是两个公式。这两个公式来告诉我们,什么是数据结构。

1、程序 = 算法 + 数据结构
2、数据结构 = 数据 + 关系

  • 数据之前存在的基本关系就是数据结构了。首先,数据有一个类型的特性,一个是基础数据类型(DT),另一个是抽象的数据类型(ADT)

    基础的数据类型无非是看你处理的是字符还是数字,或者是什么精度的整数。抽象数据类型,有点类似类的思想,对一类事物的数据进行了封装。比如,一辆汽车就是一个抽象数据类型,其中包括车的颜色、型号、特征等信息,作为对象来研究车这个整体的数据集合。

    我们最多研究的是抽象数据类型,对于抽象数据之间的关系,常常使用的基本结构是:
    表(线性表和链表)、队列和栈。
    根据一些生活常识,延伸出来一些常用的数据模型来表现一些逻辑结构:
    树、图
    另外,对于数据我们还有些常见的数据操作值得我们研究:
    查找、排序


  • 我们运行的程序处理的对象无非是数据,对于数据而言,算法决定着数据的处理方式。不同的处理方式有不同的效率。我们常见的算法有:
    枚举、递归、递推、分治、贪心等

    算法有两个重要的考量指标:时间复杂度 和 空间复杂度
    时间复杂度是语句的频度之和的数量级,这和问题规模n有关,故T(n) = O(f(n))。算法的空间复杂度为算法在运行过程中临时占用存储空间的度量,记S(n)=O(g(n))。

数据结构中的线性表

数据结构中线性表是最基础、最简单的一种数据表示形式。主要用来表示数据之间存在着什么样的关系。主要分为顺序表和链表。
数据结构无非是数据和关系(D,R)。D是数据元素的集合,当D的数量是0的时候代表是空表。数据之间存在着一种前驱和后继的关系,a[i],a[i+1]是前驱和后继的关系,表头是没有直接前驱元素的,表尾是没有后继元素的。

顺序表

顺序表中数据是用一组连续的存储单元一次存储线性表中的各个数据的。其中的关系如下表示:

Loc(ai) = L(a0) + i x d
顺序表的存储结构

顺序表的存储结构:

#define Maxsize 100
#define ElemType  int
typedef struct {
    ElemType data[Maxsize];  //顺序表的元素
    int length;              //顺序表当前的长度
}Sqlist;

顺序表的基础操作:

//--------------------------->创建与销毁
//创建表
void createList (Sqlist *L, int *a , int n) {
    //线性表不需要分配空间。
    //L = (Sqlist*)malloc(sizeof(ElemType));
    for ( int i = 0; i < n; i++) {
        L->data[i] = a[i];
    }
    L->length = n;
}
//初始化空表
void initList(Sqlist *L) {
   // L = (Sqlist*)malloc(sizeof(ElemType));
    L->length = 0;
}
//销毁表
void destroyList(Sqlist *L) {
    L->length = 0;
}

//------------------------------------>查询与遍历
//判断是否表空
int isEmpty(Sqlist *L) {
    return L->length == 0;
}
//计算表长度
int lengthOfList(Sqlist *L) {
    return L->length;
}
//输出表中数据(遍历顺序表)
void mapList(Sqlist *L) {
    for (int i = 0 ; i < L->length; i++) {
        printf("%d \n", L->data[i]);
    }
}
//得到表中第N个元素的值
int getElemOfN(Sqlist *L, int n) {
    if (n < 0 || n >= L->length) {
        return  0;
    } else {
        n = L->data[n-1];
        return n;
    }
}
//判断某数据是否在顺序表中的位置
int findNumberList(Sqlist *L , ElemType e) {
    for (int i = 0; i < L->length; i++) {
        if (L->data[i] == e) {
            return i+1;
        }
    }
    
    return 0;
}

//----------------------------------->修改和删除
//在一个位置上插入一个数据(前插)
int insertDataList(Sqlist *L, int pos, ElemType e) {
    if (pos < 0 || pos > L->length) {
        return 0;
    }
    
    for (int i = L->length; i >= pos; i--) {
        L->data[i] = L->data[i-1];
    }
    L->data[pos-1] = e;
    L->length++;
    
    return 1;
}
//删除某个位置上的一个数据
void deleteDataOfN(Sqlist *L, int n) {
    for (int i = n; i < L->length; i++) {
        L->data[i-1] = L->data[i];
    }
    L->length--;
}

顺序表优缺点

优点:
1、顺序表的逻辑结构和存储结构理解方便,编写也方便;
2、顺序表的因为是随机存取的存储结构,当我们知道起始位置,差值,很容易确定指定元素;
缺点:
1、由于这种存储结构需要系统提供连续的地址空间,对于系统紧缺的机器,可能会导致不能满足当前需求;
2、由于数据元素一般都是按照最大的数进行确定的,当实际应用中没有用到这么多数据,不必要的空间会导致资源的浪费;
3、由于表中是连续分布的,这使得我们在插入和删除做数据修改的过程中,需要把修改之后的数据进行大量的移动,极大的影响了系统的运行速度。

链表

链表的出现可以解决顺序表的一些不足。链表分为单链表、单向循环链表、双向链表、静态链表等。主要讲解单链表为主,首先单链表提出了节点的概念,一个节点存储一个数据单元并且占用一个存储块,这个节点除了存储数据元之外还有一个节点指针,这个指针对象是下一个链表元素。单链表也是通过这个节点指针对一系列的数据进行联系。

单链表节点和结构示意图

单链表的存储结构:

#define Maxsize 100
#define ElemType  int
typedef struct LNode{
    ElemType data;
    struct LNode *next;
} LinkList;

单链表的基本操作:

//------------------------------>单链表的创建
LinkList* createLinkHead(LinkList *L) {
    LinkList *t;
    ElemType inputNum;
    //先初始化一个空的链表
    L = (LinkList*)malloc(sizeof(LinkList));
    L->data = 999;  //999代表的是头
    L->next = NULL;
    //开始添加
    printf("please input:\n");
    scanf("%d", &inputNum);
//    循环添加,只到“-1”结束
    while (inputNum != -1) {
        t = (LinkList*)malloc(sizeof(LinkList));
        t->data = inputNum;
        t->next = L->next;
        L->next = t;
        scanf("%d", &inputNum);
    }
    return L;
}
//------------------------------>单链表的查询
//得出第i个元素的值
LinkList* getValueLinklistOfPos(LinkList *L, int pos) {
    LinkList *t = L;
    int i = 0;
    if (pos > lengthOfLinklist(L) || pos < 0) {
        return 0;
    }
    while (pos > i) {
        i++;
        t = t->next;
    }
    return t;
}
//遍历
void mapLinklist(LinkList *L) {
    LinkList *t = L;
    while (t->next != NULL) {
        printf("%d ", t->next->data);
        t = t->next;
    }
    printf("\n");
}
//得出元素的长度
int lengthOfLinklist(LinkList *L) {
    int l = 0;
    LinkList *t = L;
    while(t->next != NULL) {
        l++;
        t = t->next;
    }
    return l;
}

//------------------------------>单链表的添加
//尾插法
LinkList* createLinkTail(LinkList *L) {
    LinkList *t, *r;
    ElemType inputNum;
    //先初始化一个空的链表
    L = (LinkList*)malloc(sizeof(LinkList));
    L->data = 999;  //999代表的是头
    r = L;
    //开始添加
    printf("please input:\n");
    scanf("%d", &inputNum);
    //    循环添加,只到“-1”结束
    while (inputNum != -1) {
        t = (LinkList*)malloc(sizeof(LinkList));
        t->data = inputNum;
        r->next = t;
        r = t;
        scanf("%d", &inputNum);
    }
    r->next = NULL;
    return L;
}
//插入操作,将值e插入到单链表的第i个位置前面
int insertLinkList(LinkList *L, ElemType e, int pos) {
    LinkList *t = L;
    int i = 0;
    if (pos > lengthOfLinklist(L) || pos < 0) {
        return 0;
    }
    // 循环跳出,pos=i;
    while (pos > i+1) {
        t = t->next;
        i++;
    }
    LinkList *s = (LinkList*)malloc(sizeof(LinkList));
    s->data = e;
    s->next = t->next;
    t->next = s;
    return 1;
}

//------------------------------>单链表的删除
//删除第i个元素的操作节点
int deleteLinkList(LinkList *L, int pos) {
    if (pos > lengthOfLinklist(L) || pos < 0) {
        return 0;
    }
    LinkList *p = getValueLinklistOfPos(L, pos-1);
    p->next = p->next->next;
    free(p->next);
    return 1;
}
//------------------------------>单链表的修改
//修改第i个元素的操作节点
int alterLinkListFromPos(LinkList *L, int pos, ElemType e) {
    if (pos > lengthOfLinklist(L) || pos < 0) {
        return 0;
    }
    LinkList *t = getValueLinklistOfPos(L, pos);
    t->data = e;
    return 1;
}
//修改第一个值为e的元素的值
int alterLinkListFromValue(LinkList *L, ElemType e, ElemType ex) {
    LinkList *t = L;
    while (1) {
        if (t->next == NULL) {
            return 0;
        } else {
            if (t->data == e) {
                t->data = ex;
                return 1;
            } else {
                t = t->next;
            }
        }
    }
}

链表的优缺点

优点:
1、最大的优点就是克服了顺序表的最大存储空间申请的特点,用数据的时候进行分配,不使用的时候就进行释放,相对的节省了一定的空间;
2、存储的时候是靠指针的链接来进行实现的,所以克服了插入和删除元素大量移动的缺点;
缺点:
1、每个节点的指针域也会带来一定的空间占用,当Data所占空间比较少的时候,指针域的比重相对较大。所以,当考虑使用顺序表还是链表所占空间的时候,还需要具体分析;
2、链表插入和删除相对简单了,带来的问题就是查找变的相对麻烦,往往需要从头结点进行查找,增加了算法的复杂程度。

线性表小结
顺序表和链表比较基础一节。我们可以通过比较优缺点,他们是相互取长补短的,优点和缺点都是相互对称的。我们可以通过实际情况来进行选取数据的存储方式。

本章小结

我想做的是记录算法的一个系列,各种基础的、经典的算法稍微偏重一些。线性表是比较基础的一节,但是牵扯到的思路都比较明显,不算太难。另外,链表这边还包括单向循环链表、双向链表和静态链表,这不再一一说明。我的Git上有单链表、顺序表、双向链表的测试代码,可以进行简单参考。
(PS:如果哪里写的不好和有误,还希望大家指出,及时改正,希望和大家一起进步~~ > _ < ~~ !!!)
Git地址(仅供参考)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容