算法笔记 基本数据结构 线性表,可用于严卫敏数据结构c语言版的代码实验!

基本数据结构-线性表


Macre算法系列笔记是综合 严卫敏《数据结构(c语言版)》书籍,以及考研408辅导讲义–王道408计算机考研的内容上,结合 罗永浩《算法竞赛》内容,加强编码能力和解决问题的实践能力。 感谢以上所提及的个人和机构对计算机教学领域做出的杰出贡献。(应该在有一定编程语言和调试能力下尽量去coding和调试!)。

可以作为数据结构与算法课程的实验去copy本内容代码!

先记录基本数据结构具体内容,算法应用在最后!

一、线性表基本定义

一个数据结构包含逻辑结构存储结构以及作用在元素上的方法

(1)逻辑结构

线性表(linear line)是最简单的数据结构。非空表记为D=(a1, a2 , …, ai-1, ai , …, an)。用数学表达式表示为:
D =    { a i ∣ a i ∈ T , i = 1 , 2 , . . . , n , n ≥ 0 } D=\,\,\left\{ ai|ai∈T,i=1,2,...,n,n≥0 \right\} D={aiaiT,i=1,2,...,n,n0}

其是一个有限序列,表中每个表项都是相继排列的,每两个相邻表象都有直接前驱和直接后继关系,也就是说,线性表中仅存在唯一的一个表头(haed)、唯一的一个表尾(tail)。这表明表中数据之间的关系是线性表中相邻的数据元素ai-1和ai之间存在序偶关系(ai-1, ai),即ai-1是ai的前驱, ai是ai-1的后继;a1无前驱,an无后继,其它每个元素有且仅有一个前驱和一个后继。
R = { < a i − 1 , a i > ∣ a i − 1 , a i ∈ D , i = 2 , . . . , n } R\text{=}\left\{ <a_{i-1},a_i>|a_{i-1},a_i∈D,i=2,...,n \right\} R{<ai1,ai>ai1,aiD,i=2,...,n}

(2)存储结构

主要是顺序存储链式存储

顺序存储:逻辑上相邻的元素在物理位置上也相邻。

链式存储:逻辑与物理存储位置无关。

(3)作用在次数据结构上的操作:

一个线性表内:元素的增加、删除、查找等;

线性表之间:合并、比较等

二、顺序存储的线性表- 顺序表 SQlist

在这里插入图片描述

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
typedef int Elemtype; 
typedef int Status; 

2.1 静态数组

#define Maxsize 20
typedef int Status; 
// 静态数组
typedef struct Sqlsit
{
    /* data */
     Elemtype data[Maxsize];
     int length;
}Sqlist;

2.2 动态数组

typedef struct 
{
    /* data */
    Elemtype *elem;
    int length;
    int size;
}Sqlist;

2.3 方法

函数具体说明看函数里第一行注释! 对于动态的!

Sqlist initSqlist()
{
    // 初始化函数
    Sqlist L;
    L.elem = (Elemtype *)malloc(Maxsize*sizeof(Elemtype));
    if (!L.elem)
    {
        printf("初始化失败!");
        exit(0);
    }
    L.length = 0;
    L.size = Maxsize;
    return L;
}

Status creatList(Sqlist *L,int n)
{
     // 
    if(n < 0) return 0;
    if (n > L->size)
    {
        Elemtype *new = (Elemtype *)realloc(L->elem,L->size*2*sizeof(Elemtype));
        L->elem = new;
        L->size *=2;
    }
    for (int i = 0; i < n; i++)
    {
        // 用空白符结尾时,scanf会跳过空白符去读下一个字符,scanf在之前只读了10个数给数组初始化,后面必须多读一个数来作为结束信号,所以你必须再输入一个数。
        // 删除空格符号就可以
        scanf("%d",&L->elem[i]);
        L->length++;
    }
    return 1;
}

void displayTable(Sqlist t)
{
    // 打印展示 for循环打引
    for (int i = 0; i < t.length; i++)
    {
        printf("%d ",t.elem[i]);
    }
    printf("\n");
}

Status listinsert(Sqlist *L,int i,Elemtype x)
{
    // 插入 插入后整体往后移动一位。 L->elem[j+1] = L->elem[j];后一个等于其前一个。
    if (L->length>=L->size)
    {
        Elemtype *new = (Elemtype *)realloc(L->elem,sizeof(Elemtype)*L->size*2);
        L->size *= 2;
    }
    if (i < 0 || i > L->length)
    {
        printf("请输入合法的位置!");
        return 0;
    }
    for (int j = L->length-1; j >= i-1 ; j--)
    {
        L->elem[j+1] = L->elem[j];
    }
    L->elem[i-1] = x;
    L->length+=1;
    return 1;
}

Status Listclear(Sqlist *L)
{
    //清零
    //将length变为零后就没有办法通过length访问元素,相当于上进行清零的操作。
    L->length = 0;
    return 1;    
}

Status ListDestory(Sqlist *L)
{
    // 销毁一个顺序表
    free(L->elem);
    //释放后的无效指针必须置为空,不然会导致内存泄漏
    L->elem =NULL;
    L->length = 0;
    L->size = 0;
}

int ListLength(Sqlist L){
    // 获取长度
    return L.length;
}

Status ListEmpty(Sqlist L)
{
    // 判空
    if (L.length == 0) return 1;
    else return 0;
}

Status GetElem(Sqlist L,int i,Elemtype *e)
{
    if (i <= 0 || i >L.length) return 0;
    // *e = L.elem[i-1];
    e = *(L.elem +i -1);
    return 1;
    
}

Status ListDelete(Sqlist *L,int i,Elemtype *e)
{
    if (i<1 || i> L->length) return 0;
    // 取这个位置上的指针
    Elemtype *p  = &(L->elem[i-1]);
    e= *p;
    // 取尾元素的指针
    Elemtype *q = L->elem+L->length-1;
    for (++p; p<=q; p++)
    {
        *(p-1) = *p;
    }
    --L->length;
    return 1;
}

Status cmp(Elemtype a,Elemtype b)
{
    if (a == b) return 1;
    return 0;
}

int LocateElem(Sqlist L,Elemtype *e, Status (*cmp)(Elemtype,Elemtype))
{
    // 找到与e相同的第一个元素,
    int i  =1;
    Elemtype *p = L.elem;
    while (i <= L.length && !(*cmp)(*p++,*e)) ++i;
    if (i < L.length) return i;
    return 0;
}

void Union_1(Sqlist *L1,Sqlist L2)
{
    int L1_len =L1->length , L2_len = ListLength(L2);
    Elemtype *e;
    
    for (int i = 1; i <= L2.length; i++)
    {
        /* code */
        // GetElem(L2,i,e);
        e = L2.elem+i-1;
        
        if (!LocateElem(*L1,e,cmp)) listinsert(L1,++L1->length,*e);
    }
     
}

// void MergeList(Sqlist L1,Sqlist L2,Sqlist *L3)
// {
//     // *L3 = initSqlist();
//     int i= 1,j =1,k =0;
//     int len1 = ListLength(L1),len2 = ListLength(L2);
//     Elemtype *a,*b;
//     while ((i <= len1)&&(j <= len2))
//     {
//         a = L1.elem+i-1;
//         b = L2.elem+j-1;
//         if (*a <= *b)
//         {
//             listinsert(L3,++k,*a);
//             ++i;
//         }else{
//             listinsert(L3,++k,*b);
//             ++j;
//         }    
//     }
//     while (i<=len1)
//     {
//         a = L1.elem+i-1;
//         listinsert(L3,++k,*a);
//         ++i;
//     }
//     while (j<=len2)
//     {
//         b = L2.elem+j-1;
//         listinsert(L3,++k,*b);
//         ++j;
//     }
//     L3->length-=1;
// }

void MergeListSq(Sqlist L1,Sqlist L2,Sqlist *L3)
{
    Elemtype *p1 = L1.elem,*p2 = L2.elem;
    L3->length = L1.length+L2.length;
    L3->size = L3->length;
    L3->elem = (Elemtype *)malloc(L3->size*sizeof(Elemtype));
    Elemtype *P3 = L3->elem;
    if (!L3->elem) exit(0);
    Elemtype *p1_e = L1.elem+L1.length-1,*p2_e =L2.elem+L2.length-1;
    while (p1 <= p1_e && p2 <= p2_e)
    {
        if (*p1 < *p2) *P3++ = *p1++;
        else *P3++ = *p2++; 
    }
    while (p1 <= p1_e) *P3++ = *p1++;
    while (p2 <= p2_e) *P3++ = *p2++;
}

可以在main里调用和测试方法;

// 上面加上
int main()
{
    Sqlist L = initSqlist();
    Sqlist L1 = initSqlist();
    Sqlist L3 = initSqlist();
    int a[5] ={1,3,5,7,9};
    int b[5] = {2,4,6,8,10};
    
    // 用两个数组初始化线性表;
    for (int i = 1; i <= 5; i++)
    {
        /* code */
        L.elem[i-1] = a[i-1];
        L.length++;
    }
    for (size_t i = 1; i <= 5; i++)
    {
        L1.elem[i-1] = b[i-1];
        L1.length++;
    }
    
    // 方法
    displayTable(L);
    displayTable(L1);
    MergeListSq(L,L1,&L3);
    
}

三、链式存储的线性表-单链表 Linklist

在这里插入图片描述

3.1 静态链表

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传]在这里插入图片描述

#include <stdio.h>
#define Maxsize 1000

typedef int Elemtype;

typedef struct{
    Elemtype data;
    int cur; // 游标 指示下一个
}node,SlinkList[Maxsize];


int main()
{
    
    return 0;
}

3.2 动态链表

#include <stdio.h>
typedef int Elemtype;
typedef int Status;
typedef struct 
{
    Elemtype data;
    struct LNode *next;

}LNode,*Linklist;

3.3 方法

void List_headInsert(Linklist *L)
{
    // 头插法建立单链表 带头结点
    // 传入的是一个指向指针变量的指针
    LNode *s; Elemtype x;
    (*L) = (Linklist)malloc(sizeof(LNode));
    (*L)->next = NULL;
    scanf("%d",&x);
    while (x!= 9999)
    {
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        s->next = (*L)->next;
        (*L)->next = s;
        scanf("%d",&x);
    }
}

void List_tailInsert(Linklist *L)
{
    // 尾插法建立单链表 带头结点
    Elemtype x;
    (*L) = (Linklist)malloc(sizeof(LNode));
    LNode *s,*r = (*L);
    scanf("%d",&x);
    while (x!=9999)
    {
        s = (Linklist)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        r = s;
        scanf("%d",&x);
    }
    r->next = NULL;
}

LNode *Getelem_ID(LNode L,int i)
{
    // 按序号查找
    if (i<1) return NULL;
    int j = 1;
    LNode *p = L.next;
    while (p!= NULL && j < i)
    {
        p = p->next;
        j++;
    }
    return p;
}

LNode *Getelem_V(LNode L,Elemtype x)
{
    // 指向首元素
    LNode *p = L.next; 
    while (p!= NULL && p->data != x) p = p->next;
    return p;
}

void showList(LNode L)
{
    Linklist j = L.next;
    while(j)
    {
        printf("%d ",j->data);
        j = j->next;
    }
}

Status ListInsert_L(Linklist *L,int i,Elemtype x)
{
    // 在第i个位置之前插入x;
    Linklist p = *L;
    int j = 0;
    while ( p && j<i-1) { 
        p = p->next;
        ++j;
    }
    if( !p || j >i-1) return 0; //第i个位置的节点不存在
    Linklist s = (Linklist)malloc(sizeof(LNode));
    s->data = x;
    s->next = p->next;
    p->next = s;
    return 1;
}

Status ListDelete(Linklist *L,int i,Elemtype *e)
{
    // 删除第i个位置的元素
    Linklist p = *L;
    int j = 0;
    while (p->next && j<i-1)
    {
        p = p->next;
        j++;
    }
    if (!(p->next) || j>i-1) return 0;
    Linklist q = p->next;
    p->next = q->next;
    *e = q->data;
    free(q);
}

// 有错误
void MergeList(Linklist L1,Linklist L2,Linklist *L3)
{
    Linklist p1 = L1->next, p2 = L2->next;
    Linklist p3 = *L3;
    p3->next = NULL;
    while (p1 && p2)
    {
        if (p1->data <= p2->data)
        {
            p3->next = p1;p3 = p1;p1 = p1->next;            
        }
        else{
            p3->next = p2;p3 = p2; p2 = p2->next;
        }
    }
    p3->next = p1 ? p1 : p2;
}

测试,运行时输入值,输入9999 时推出插入,采用头差,也可以采用尾插。

int main()
{
    Linklist L;
    Linklist L1;
    List_headInsert(&L);
    Linklist k = L->next;
    while(k)
    {
        printf("%d ",k->data);
        k = k->next;

    }
    return 0;
}

四、算法应用

约瑟夫问题

题目:n个人围成一圈,初始编号从1~n排列,从约定编号为x的人开始报数,数到第m个人出圈,接着又从1开始报数,报到第m个数的人又退出圈,以此类推,最后圈内只剩下一个人,这个人就是赢家,求出赢家的编号。

(1)动态链表
#include<bits/stdc++.h>

struct node{
    int data;
    struct node * next;
};

int main(){
    // 处理输入输出
    int n,m;
    scanf("%d %d",&n,&m);
    // 初始化动态链表
    node *head,*now,*p,*prev;
    head = new node;
    head->data = 1; head->next = NULL;
    now = head;
    for (int i = 2; i <= n; i++){
        p = new node; p->data = i; p->next = NULL;
        now->next = p;
        now = p;
    }
    // 循环链表,头尾链接起来
    now->next = head;
   //
   now = head;
   prev = head;
   while((n--)> 1){
    for (int i = 1; i < m; i++){
        prev = now;
        now = now->next;
    }
    printf("%d ",now->data);
    prev->next = now->next;
    delete now;
    now = prev->next;
   }
   // 由于最后一个已经是确定的了,所以只要最后输出一个而不是再循环m次,所以循环只到1;
   printf("%d ",now->data);
   delete now;
   return 0;
}
(2) 静态链表

结构体数组单向:

#include <bits/stdc++.h>
const int N = 105; // 要在全局声明

// 结构体数组单向链表
struct node{
    int id,nextid;
}nodes[N];

int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    nodes[0].id = 0;nodes->nextid  =1;
    for (int i = 1;i <= n; i++){nodes[i].id = i;nodes[i].nextid = i+1;}
    nodes[n].nextid =1;
    int now=1;int prve = 1;
    while((n--) >1){
        for (int i = 1; i < m; i++){
            prve = nodes[now].id;
            now = nodes[now].nextid;
        }
        printf("%d ",nodes[now].id);
        nodes[prve].nextid = nodes[now].nextid;
        now = nodes[prve].nextid;
    }
    printf("%d ",nodes[now].id);
    return 0;
}

结构体数组双向:

#include<bits/stdc++.h>
const int N = 105;
struct node
{
    int id;
    // int data;
    int preid,nextid;
}nodes[N];

int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    nodes[0].nextid=1;
    for (int i = 1; i <= n; i++){
        nodes[i].id= i;
        nodes[i].preid = i-1;
        nodes[i].nextid = i+1;
    }
    nodes[1].preid = n;
    nodes[n].nextid = 1;
    int now = 1;
    int prev,nextv;
    while ((n--)>1){
        for (int i = 1; i < m; i++) now = nodes[now].nextid;
        printf("%d ",nodes[now].id);
        prev = nodes[now].preid;
        nextv = nodes[now].nextid;
        nodes[prev].nextid = nodes[nextv].id;
        nodes[nextv].preid = nodes[prev].id;
        now = nextv;
    }
    printf("%d ",nodes[now].id);
    return 0;
    
}

数组单向链表:

#include<bits/stdc++.h>

int A[150];

int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i = 1; i < n ; i ++) A[i] = i+1;
    A[n] = 1;
    int now =1;int prev = 1;
    while ((n--)>1){
        for(int i = 1;i < m; i++){
            prev = now;
            now = A[now];
        }
        printf("%d ",now);
        A[prev] = A[now];
        now = A[prev];
    }
    printf("%d ",now);
    return 0;
    
}
(3)STL list

以后更新博客!

s[now].nextid;
nodes[prev].nextid = nodes[nextv].id;
nodes[nextv].preid = nodes[prev].id;
now = nextv;
}
printf("%d ",nodes[now].id);
return 0;

}




数组单向链表:

~~~C++
#include<bits/stdc++.h>

int A[150];

int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i = 1; i < n ; i ++) A[i] = i+1;
    A[n] = 1;
    int now =1;int prev = 1;
    while ((n--)>1){
        for(int i = 1;i < m; i++){
            prev = now;
            now = A[now];
        }
        printf("%d ",now);
        A[prev] = A[now];
        now = A[prev];
    }
    printf("%d ",now);
    return 0;
    
}
(3)STL list

以后更新博客!

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值