数据结构(C语言版本)

数据结构(C语言版本)

第1章 绪论

1.常用的数据结构类型:集合、线性、树形、图状。

2.数据结构:

  • 逻辑结构:数据元素之间的关系
  • 存储结构:数据结构在计算机中的表示。存储结构分为:顺序存储结构和链式存储结构。

3.算法是对特定问题求解步骤的一种描述,算法具有如下特性:有穷性、确定性、可行性、输入、输出。

4.算法的度量:

  • 时间复杂度
  • 空间复杂度

第二章 线性表

1.线性表的定义:

  • 存在唯一一个“第一个”元素
  • 存在唯一一个“最后一个”元素
  • 除第一个元素外,每一个元素都有且只有一个前驱
  • 除最后一个元素外,每个元素都有且只有一个后继

2.线性表合并的方法:

  • 将表A中的元素逐个和B中的比较,不同就加入到B中。时间复杂度为O(len(A)*len(B))
  • AB是有序排列的前提下,使用两个指针分别指向A和B,将两者较小的元素插入到C中,然后移动较小的指针,直到全部插入到C。时间复杂度为O(len(A)+len(B))

3.线性表的顺序实现:满足LOC(A(i+l))=LOC(A(i))+l,LOC表示元素地址。特点:下标读取快O(1),插入删除O(n)。

#include <stdlib.h>
#ifndef SEQUENCE_LINER_LIST_H
#define SEQUENCE_LINER_LIST_H

/*
    线性表的顺序实现
*/
#define LIST_INIT_SIZE 100  //初始分配量
#define LIST_INCREMENT 10   //增量
#define LIST_TYPE int       //存储类型

typedef struct strSequenceLinerList
{
    LIST_TYPE *elem;        //存储空间基址
    unsigned int length;    //当前长度
    unsigned int listSize;  //当前存储容量
}SequnceLinerList;

static enum Status
{
    OK,
    FAILED,
    OVERFLOW
};

/* 线性表初始化 */
Status initSequenceLinerList(SequnceLinerList& list)
{
    list.elem = (LIST_TYPE *)malloc(sizeof(LIST_TYPE)*LIST_INIT_SIZE);
    if (!list.elem)
    {
        return OVERFLOW;
    }
    list.length = 0;
    list.listSize = LIST_INIT_SIZE;
    return OK;
}

/* 扩展 */
Status resizeSequenceLinerList(SequnceLinerList& list)
{
    printf("Resize...\n");
    list.elem = (LIST_TYPE*)realloc(list.elem, sizeof(LIST_TYPE)*(list.listSize + LIST_INCREMENT));
    if (!list.elem)
    {
        return OVERFLOW;
    }
    list.listSize += LIST_INCREMENT;
    return OK;
}

/* 打印 */
void printSequnceLinerList(SequnceLinerList& list)
{
    printf("Begin print list...\n");
    printf("length=%d,listSize=%d.\n",list.length,list.listSize);
    unsigned int i = 0;
    for (; i < list.length-1;++i)
    {
        printf("%d,",list.elem[i]);
    }
    printf("%d\n", list.elem[i]);
    printf("End print list.\n");
}

/* 线性表插入:position表示插入的位置,从1开始。第一个元素是list.elem[0] */
Status insertSequenceLinerList(SequnceLinerList& list, unsigned int position, LIST_TYPE value)
{
    if (position<1 || position>list.length+1)
    {
        return FAILED;
    }
    if (list.length >= list.listSize)
    {
        Status res = resizeSequenceLinerList(list);
        if (OK != res)
        {
            return FAILED;
        }
    }

    LIST_TYPE* p = &list.elem[position -1];
    LIST_TYPE* q = &list.elem[list.length];
    for (; p != q; --q)
    {
        *(p + 1) = *p;
    }
    list.length++;
    *p = value;
    return OK;
}

/* 删除元素 */
Status deleteSequenceLinerList(SequnceLinerList& list, unsigned int position)
{
    if (position<1 || position>list.length)
    {
        return FAILED;
    }

    LIST_TYPE* p = &list.elem[position - 1];
    LIST_TYPE* q = &list.elem[list.length - 1];
    for (; p != q; ++p)
    {
        *p = *(p+1);
    }
    --list.length;
    return OK;
}

/* 查找:第一个值的下标 */
unsigned int findSequenceLinerList(SequnceLinerList& list, int value)
{
    for (unsigned int i = 0; i < list.length;++i)
    {
        if (value == list.elem[i])
        {
            return i;
        }
    }
    return -1;
}

/* 排序(冒泡) */
void sortSequeceLinerList(SequnceLinerList& list)
{
    unsigned int i = 0;
    unsigned int j = 0;
    for (; i < list.length-1;++i)
    {
        for (j = i + 1; j < list.length; ++j)
        {
            if (list.elem[i]>list.elem[j])
            {
                LIST_TYPE tmp = list.elem[i];
                list.elem[i] = list.elem[j];
                list.elem[j] = tmp;
            }
        }
    }
}

/* 销毁 */
void destroySequenceLincerList(SequnceLinerList& list)
{
    delete list.elem;
    list.elem = NULL;
}

#endif

4.线性表的链式实现:通过p=p.next查找具体位置的链表。特点:插入、删除快O(n)。

#include <stdio.h>
#include <stdio.h>
#ifndef LINK_LINER_LIST_H
#define LINK_lINER_LIST_H
#define LINK_LIST_TYPE int

/*
    线性表的链表实现
*/
typedef struct strLinkLinerList
{
    LINK_LIST_TYPE data;
    struct strLinkLinerList* pNext;
}LinkLinerList;

LinkLinerList* head = NULL;

/* 链表初始化 */
Status initLinkLinerList()
{
    if (NULL == head)
    {
        head = (LinkLinerList*)malloc(sizeof(LinkLinerList));
        if (!head)
        {
            return OVERFLOW;
        }
        head->pNext = NULL;
        return OK;
    }
    else
    {
        return FAILED;
    }
}

/* 添加元素 */
Status insertLinkLinerList(LINK_LIST_TYPE value)
{
    if (NULL == head)
    {
        return FAILED;
    }
    LinkLinerList* p = head;
    while (p->pNext)
    {
        p = p->pNext;
    }
    LinkLinerList* tmp = (LinkLinerList*)malloc(sizeof(LinkLinerList));
    if (!tmp)
    {
        return OVERFLOW;
    }
    tmp->data = value;
    tmp->pNext = NULL;
    p->pNext = tmp;
    return OK;
}

/*打印*/
void printLinkLinerList()
{
    printf("Begin print...\n");
    if (NULL == head || NULL == head->pNext)
    {
        printf("List is null.");
    }
    LinkLinerList* p = head->pNext;
    while (p->pNext)
    {
        printf("%d,",p->data);
        p = p->pNext;
    }
    printf("%d\n", p->data);
    printf("End print.\n");
}

/* 排序 */
Status sortLinkLinerList()
{
    if (NULL == head || NULL == head->pNext)
    {
        return FAILED;
    }
    LinkLinerList* p = head->pNext;
    LinkLinerList* q = p->pNext;
    while (p)
    {
        q = p->pNext;
        while (q)
        {
            if (p->data > q->data)
            {
                LINK_LIST_TYPE tmp = p->data;
                p->data = q->data;
                q->data = tmp;
            }
            q = q->pNext;
        }
        p = p->pNext;
    }
    return OK;
}

/* 长度 */
unsigned int lengthLinkLinerList()
{
    if (head == NULL || head->pNext == NULL)
    {
        return 0;
    }
    LinkLinerList* p = head->pNext;
    unsigned int length = 0;
    while (p)
    {
        p = p->pNext;
        length++;
    }
    return length;
}

/* 删除 */
Status deleteLinkLinerList(unsigned int position)
{
    if (position > lengthLinkLinerList() || position < 1)
    {
        return FAILED;
    }
    else
    {
        LinkLinerList* p = head;
        LinkLinerList* q = p->pNext;
        if (NULL == p || NULL == q)
        {
            return FAILED;
        }
        while (--position)
        {
            p = p->pNext;
            q = p->pNext;
        }
        p->pNext = q->pNext;
        free(q);
        return OK;
    }
}

/* 销毁 */
void destroyLinkLinerList()
{
    if (NULL == head)
    {
        return;
    }
    else
    {
        LinkLinerList* p = head->pNext;
        LinkLinerList* q = p;
        while (p)
        {
            p = p->pNext;
            free(q);
            q = p;
        }
    }
}

#endif

上面实现的是线性表的链式结构。此外,线性表通过链表还可以实现:

  • 循环列表:表最后的一个节点的指针指向表头
  • 双列表:指针可以指向下一个元素或者上一个元素

5.线性表的用途:

  • 一元多项式的表示和相加

第3章 栈和队列

1.栈和队列是特殊的线性表。

2.栈是先进后出的线性表,其表示:typedef struct{Type *base;Type *top; int stacksize;}SqStack;其中base始终指向栈底,top随元素的添加一直指向栈顶。可以有顺序实现和链表实现。

3.栈的应用举例:

  • 数制转换
  • 括号匹配
  • 行编辑器帮助处理错误输入
  • 迷宫求解
  • 表达式求解
  • 实现递归

3.队列是先进先出的线性表。可以由链表实现和顺序实现。

第四章 串

1.串是由零到多个字符组成的字符序列。

2.串的模式匹配算法(查找子串):

  • 找到主串中第一个等于子串首字符的位置,开始逐步遍历子串和主串:时间复杂度O(n*(m-n+1)),其中m,n是主串、子串长度
  • kmp算法:关键是部分匹配值的计算("部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度)。搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置)。时间复杂度O(n+m)。KMP算法仅当子串与主串之间存在很多"部分匹配"的情况下才快的多。详见http://kb.cnblogs.com/page/176818/

第五章 数组和广义表

1.广义表(Lists,又称列表)是一种非线性的数据结构,是线性表的一种推广。即广义表中放松对表元素的原子限制,容许它们具有其自身结构。

第六章 树和二叉树

1.树的相关概念:

  • 度:节点的子树数目称之为节点的度。度为0的节点称之为叶子。
  • 深度:树中结点的最大层次。

2.二叉树子节点至多有两个,且有左右之分。二叉树有五种基本形态:空、根、右子树为空、左右子树非空、左子树为空。二叉树的性质:

  • 第i层有2^(i-1)个节点
  • 深度为k的二叉树至多2^k-1个节点
  • 终端节点数为n,度为2的节点数为m,则n=m+1
  • 具有n个结点的完全二叉树的深度是(log2N)+1

3.二叉树分类:

  • 满二叉树:深度为k且有2^k-1个结点的二叉树
  • 完全二叉树:深度为k,有n个结点的二叉树,每个结点的编号与深度为k的满二叉树编号一一对应

4.二叉树的存储结构:

  • 顺序结构:按照完全二叉树的编号将其存放在一位数组中标有i-1的分量中。
  • 链表结构:typedef struct BitNode{ElemType data; struct BitNode *lchild,*rchild}BitNode;

5.二叉树的遍历:

  • 先序(根)遍历
  • 中序(根)遍历
  • 后序(根)遍历
    先根和后根反映的是双亲与孩子节点的关系,中根反映的是兄弟节点之间的左右次序。对于表达式而言,这三种遍历分别前缀表达式(波兰表达式)、中缀表达式和后缀表达式(逆波兰表达式)。

6.二叉树的确定:

  • 已知先根和中根遍历可以建立唯一二叉树
  • 已知后根和中根遍历可以建立唯一二叉树
  • 已知先根和后根遍历不可以建立唯一二叉树

7.二叉树的遍历可以使用递归实现,其非递归中根遍历的算法是(使用栈操作):

[图片上传失败...(image-5f478f-1524397579659)]

8.二叉树从根开始分层从左至右遍历算法是(使用队列操作):

image

9.线索二叉树:指向前驱或者后继的节点的链成为线索。线索二叉树使用的节点结构为:data、left、right、ltag、rtag。其中ltag(rtag)=0表示子树,=1表示前驱(后继)节点。

10.赫夫曼树又称最优树,是一类带权路径长度(子叶到根的路径个数)最短的树。赫夫曼树的构造算法:赫夫曼算法:

  • (1)以权值分别为W1,W2...Wn的n各结点,构成n棵二叉树T1,T2,...Tn并组成森林F={T1,T2,...Tn},其中每棵二叉树 Ti仅有一个权值为 Wi的根结点;
  • (2)在F中选取两棵根结点权值最小的树作为左右子树构造一棵新二叉树,并且置新二叉树根结点权值为左右子树上根结点的权值之和(根结点的权值=左右孩子权值之和,叶结点的权值= Wi)
  • (3)从F中删除这两棵二叉树,同时将新二叉树加入到F中;
  • (4)重复(2)、(3)直到F中只含一棵二叉树为止,这棵二叉树就是Huffman树。
image

11.赫夫曼树的应用:

  • 不同分数段评定优良中差,可以按照分数出现比例为权值构造赫夫曼数,优化程序判断次序
  • 赫夫曼编码

第七章 图

1.图的遍历算法:

  • 深度优先算法
  • 广度优先算法

第八章 动态管理内存

第九章 查找

1.查找算法(详见https://www.cnblogs.com/yw09041432/p/5908444.html)。平均查找长度(Average Search Length,ASL):需和指定key进行比较的关键字的个数的期望值,称为查找算法在查找成功时的平均查找长度。对于含有n个数据元素的查找表,查找成功的平均查找长度为:ASL = Pi*Ci的和。Pi:查找表中第i个数据元素的概率。Ci:找到第i个数据元素时已经比较过的次数。

  • (1)顺序表查找:顺序查找:
    • 要求:存储结构为顺序存储或者链表存储
    • 思想:顺序依次查找
    • ASL:(1/n)*(1+2+...+n)=(n+1)/2
    • 时间复杂度:O(n)
  • (2)二分查找、折半查找:
    • 要求:有序顺序存储列表
    • 思想:先将查找值与中间值比较,查找不成功折半查找区间
    • ASL:log2(n+1)
    • 时间复杂度:O(log2n)
  • (3)插值查找:
    • 要求:有序顺序存储列表
    • 思想:基于二分查找算法,将查找点的选择改进为自适应选择(由mid=low+1/2(high-low)改为mid=low+(key-a[low])/(a[high]-a[low])(high-low),),可以提高查找效率。
    • 时间复杂度:O(log2n)
  • (4)斐波那契额查找:
    • 要求:有序顺序存储列表
    • 思想:依然是对查找点的优化,采用Fibonacci数组,找到对于当前长度的有序表的黄金分割点,作为每次的中间值。
    • 时间复杂度:O(log2n)。平均性能,菲波那切查找优于折半查找,最坏情况低于折半查找。
  • (5)二叉查找树:
    • 要求:需要首先二叉查找树(左子树<根<右子树)
    • 思想:先对待查找的数据进行生成树,确保树的左分支的值小于右分支的值,然后在就行和每个节点的父节点比较大小,查找最适合的范围
    • 时间复杂度:O(log2n),最坏O(n),原因是没有保持平衡,形成单支树
  • (6)平衡二叉树AVL:
    • 要求:二叉查找树的基础上,需要进行树的平衡
    • 时间复杂度:一直是O(log2n)
    • 此外,在此基础上还有2-3树,2-3-4树,B+树,红黑树等。

2.上述算法中:

  • 顺序表查找:(1)
    • 优点:简单
    • 缺点:效率低O(n)
  • 有序表查找:(2)/(3)/(4)
    • 优点:时间复杂度低O(log2n)
    • 缺点:有序表的插入和删除性能是比较差的

第十章 第十一章 排序

1.排序算法的稳定性:经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。例如冒泡排序是稳定的,但是如果交换条件改为a[j].key>=a[j+1].key,就是不稳定的。

2.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。

3.常见的8种内部排序算法有(详见https://www.cnblogs.com/RainyBear/p/5258483.html):

  • 插入排序:将第一个元素看成是有序的序列,之后的元素看成是未排序的序列,然后遍历未排序的序列,将其插入到有序序列中
  • 希尔排序:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序
  • 选择排序:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  • 冒泡排序:比较相邻元素,如果前面的大就交换
  • 归并排序
  • 快速排序
  • 堆排序
  • 基数排序
排序算法.jpg

第十二章 文件

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

推荐阅读更多精彩内容

  • 第一章 绪论 什么是数据结构? 数据结构的定义:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。 第二章...
    SeanCheney阅读 5,735评论 0 19
  • 课程介绍 先修课:概率统计,程序设计实习,集合论与图论 后续课:算法分析与设计,编译原理,操作系统,数据库概论,人...
    ShellyWhen阅读 2,252评论 0 3
  • B树的定义 一棵m阶的B树满足下列条件: 树中每个结点至多有m个孩子。 除根结点和叶子结点外,其它每个结点至少有m...
    文档随手记阅读 13,149评论 0 25
  • 1、线性表、栈和队列等数据结构所表达和处理的数据以线性结构为组织形式。栈是一种特殊的线性表,这种线性表只能在固定的...
    雾熏阅读 2,382评论 0 10
  • 海德格尔在《存在与时间》中阐述了死是一种存在可能性,人的存在就是向着这种可...
    简易小姐阅读 298评论 0 1