考研数据结构重要知识点

本文详细探讨了数据结构中与考研相关的重点内容,包括逻辑结构与物理结构的概念,线性表的链表操作,排序算法如选择排序、希尔排序、直接插入排序的原理和代码实现,以及二叉树的性质、存储结构和平衡二叉树。此外,还介绍了图算法的基本概念、最短路径、最小生成树的Prim和Kruskal算法,以及查找算法中的KMP。
摘要由CSDN通过智能技术生成

数据结构

逻辑结构与物理结构

逻辑结构

数据对象中数据元素之间的相互关系

  1. 集合
  2. 线性
  3. 树形
  4. 图形

物理结构

数据的逻辑结构在计算机中的存储形式

  1. 顺序
  2. 链式

线性表

链表操作

code
typedef struct Node {
   
    int data;
    struct Node *next;
} Node;

int getElem(Node *L, int i) {
   
    Node *p;
    p = L->next;
    int j = 1;
    while (p && j < i) {
   
        p = p->next;
        j++;
    }
    if (p == nullptr || j > i)
        return -1;
    return p->data;
}

int insert(Node *L, int i, int target) {
   
    int j = 1;
    Node *p;
    p = L;
    while (p && j < i) {
   
        p = p->next;
        j++;
    }
    if (!p || j > i) {
   
        return -1;
    }
    Node *tmp = (Node *) malloc(sizeof(Node));
    tmp->data = target;
    tmp->next = p->next;
    p->next = tmp;
    return 0;
}

int listDelete(Node *L, int i) {
   
    int j = 1;
    Node *p;
    p = L;
    while (p && j < i) {
   
        p = p->next;
        j++;
    }
    if (p->next == nullptr || j > i)
        return -1;
    Node *tmp = p->next;
    p->next = tmp->next;
    free(tmp);
    return 0;
}

int createListHead(Node *L, int n) {
   //头插法
    Node *p;
    int i = 0;
    L = (Node *) malloc(sizeof(Node));
    L->next = nullptr;
    srand(time(0));
    for (int i = 0; i < n; i++) {
   
        p = (Node *) malloc(sizeof(Node));
        p->data = rand() % 100;
        p->next = L->next;
        L->next = p;
    }
    return 0;
}

int createListTail(Node *L, int n) {
   //尾插法
    Node *p, *tmp;
    srand(time(0));
    L = (Node *) malloc(sizeof(Node));
    L->next = nullptr;
    p = L;
    for (int i = 0; i < n; i++) {
   
        tmp = (Node *) malloc(sizeof(Node));
        tmp->data = rand() % 100;
        p->next = tmp;
        p = tmp;
    }
    p->next = nullptr;
    return 0;
}

int reverseList(Node *L) {
   
    Node *p, *q, *r;
    if (L->next != nullptr)
        p = L->next;
    else
        return -1;
    L->next = nullptr;
    q = nullptr;
    while (p) {
   
        r = p->next;
        p->next = q;
        q = p;
        p = r;
    }
    L->next = p;
    return -1;
}

排序

性质

  • 元素的移动次数与关键字的初始排列次序无关的是:基数排序
  • 元素的比较次数与初始序列无关是:选择排序
  • 算法的时间复杂度与初始序列无关的是:直接选择排序
  • 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法
  • 总排序趟数与初始状态无关的有:(除了快速排序和优化的冒泡,其他都是)
  • 算法复杂度与初始状态无关的有:堆排序、归并排序、选择排序、基数排序
  • 元素总比较次数与初始状态无关的有:选择排序、基数排序
  • 元素总移动次数与初始状态无关的有:归并排序、基数排序。

选择排序

算法思想

选择排序,从头至尾扫描序列,找出最小的一个元素,和第一个元素交换,接着从剩下的元素中继续这种选择和交换方式,最终得到一个有序序列。
在这里插入图片描述

code
public class Selection {
   
    public static void sort(int[] arr){
   
        for(int i=0; i<arr.length-1; i++) {
   
            int minPos = i;
            for (int j = i; j < arr.length; j++) {
   
                if (arr[j] < arr[minPos]) {
   
                    minPos = j;//找出当前最小元素的位置
                }
            }
            if(arr[minPos]!=arr[i]) {
   
                swap(arr,minPos,i);
            }
        }
    }
    public static void swap(int[] arr,int a,int b){
   
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

希尔排序

算法思想

希尔排序是记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

操作步骤

在这里插入图片描述

初始时,有一个大小为 10 的无序序列。

  1. 在第一趟排序中,我们不妨设 gap1 = N / 2 = 5,即相隔距离为 5 的元素组成一组,可以分为 5 组。
  2. 接下来,按照直接插入排序的方法对每个组进行排序。
    在第二趟排序中,我们把上次的 gap 缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组。
  3. 按照直接插入排序的方法对每个组进行排序。
  4. 在第三趟排序中,再次把 gap 缩小一半,即gap3 = gap2 / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组。
  5. 按照直接插入排序的方法对每个组进行排序。此时,排序已经结束。
code
public static void shellSort(int a[]) {
   
    int d= a.length;//gap的值
    while (true){
   
        d = d/ 2;//每次都将gap的值减半
        for (int x = 0; x< d; x++) {
   //对于gap所分的每一个组
            for (int i = x+ d; i < a.length; i= i + d) {
   //行插入排序
                int temp= a[i];
                int j;
                for (j= i - d; j>= 0 && a[j] > temp;j = j - d){
   
                    a[j+ d] = a[j];
                }
                a[j+ d] = temp;
            }
        }
        if (d==1) {
   //gap==1,跳出循环
                break;
        }
    }
}

直接插入排序

算法思想

将数组的第一个数认为是有序数组,从后往前(从前往后)扫描该有序数组,把数组中其余n-1个数,根据数值的大小,插入到有序数组中,直至数组中的所有数有序排列为止。这样的话,n个元素需要进行n-1趟排序!!!
在这里插入图片描述

操作步骤

4个数字4,6,7,5进行从大到小的排序
把第一个数4插入到空的有序数组中的第一个位置上,得到新数字序列4;

  1. 从后往前扫描有序数组,将第二个数字6和有序数组中的4进行比较,6大于4,此时将4后移一个位置。此时已经扫描完有序数组中的数,将6插入到4的前面(有序数组的第一个位置),得到新数字序列6,4;
  2. 从后往前扫描有序数组,先将第三个数字7和有序数组中的4进行比较,7大于4,此时将4后移一个位置;再将7和有序数组中的6进行比较,7大于6,此时将6后移一个位置。此时已经扫描完有序数组中的数,将7插入到6的前面(有序数组的第一个位置),得到新数字序列7,6,4;
  3. 从后往前扫描有序数组,先将第四个数字5和有序数组中的4进行比较,5大于4,此时将4后移一个位置;再将5和有序数组中的6进行比较,5小于6,由于有序数组就按照从大到小排列的,此时直接把5插入到4的前面即可!不需要再和7进行比较!最后,得到新数字序列7,6
code
#include<iostream>
#include<cstdio>
using namespace std;
#define N 5
int a[N];//有序数组

int main ( ) {
   
    int i, k, x;
    for (i=0; i<N; i++) {
   
        scanf ("%d", &x);
        for ( k=i; k>0; k-- ) {
            /* 从后向前比较 */
            if ( a[k-1] > x )    //x前面的数比它大
                a[k]=a[k-1];         /* 将大数向后移动*/
            else
                break; /* 找到插入的位置,退出 */
        }
        a[k] = x;  /* 完成插入操作 */
    }
    for (i=0; i<N; i++)
        printf("%d ", a[i]);
    return 0;
}

堆排序

int h[1000];
int n = 1000;

void siftDown(int i) {
   
    int t, flag = 0;
    while (i * 2 < n && flag == 0) {
   
        if (h[i] < h[i * 2]) {
   
            t = i * 2;
        } else
            t = i;
        if (i * 2 + 1 <= n) {
   
            if (h[t] < h[i * 2 + 1]) {
   
                t = i * 2 + 1;
            }
        }
        if (t != i) {
   
            int tmp = h[t];
            h[t] = h[i];
            h[i] = tmp;
            i = t;
        } else
            flag = 1;
    }
}

void siftUp(int i) {
   
    int flag = 0;
    if (i == 1)
        return;
    while (i != 1 && flag == 0) {
   
        
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值