美文网首页
线性表_链式结构

线性表_链式结构

作者: Mad_Elliot | 来源:发表于2019-02-13 11:03 被阅读0次

指针是变量,存的是地址。
结构特点:逻辑上相邻的数据元素在物理上不一定相邻。
设计思想:牺牲空间效率换取时间效率。

malloc():分配内存空间返回地址
用法:void *malloc(unsigned size)
功能:在内存的动态存储区分配1个长度为 size的连续空间。
返回值:申请成功,则返回新分配内存块的起始地址;否则,返回NULL
注:malloc()函数的返回值是一个无类型指针,其特点是可以指向任何类型的数据。但在实际使用malloc()函数时,必须将其返回值强制转换成被赋值指针变量的数据类型,以免出错。

sizeof() :获取变量类型长度
·格式:sizeof(变量名/类型名)
·功能:求变量/类型占用的内存字节数(正整数)。

free():释放内存空间
·用法:void free(void *ptr)
·功能:释放 由ptr指向的内存块(ptr是调用malloc() 函数的返回值)。
·返回值:无。

定义:(存储的数据类型及指向自身类型的指针类型)

//SingleNode是自定义结构类型名称
typedef struct SingleNode 
{
    ElemType data; //数据
    struct SingleNode *next; //指向下个节点指针
}SingleLinkList;

ListInstialize() 初始化:分配头结点空间,头指针指向该空间,头结点的next指向NULL

//申请头结点空间,头指针指向头结点
void ListInstialize(SingleLinkList **head)
{
    *head = (SingleLinkList *)malloc(sizeof(SingleLinkList));
    (*head)->next = NULL;
}

注:因为改变的是头指针(指向头结点的指针),所以需要两个*

ListLength() 求元素个数
步骤:从头结点的next开始,不为空size+1,为空则循环条件不成立,最后返回size

int ListLength(SingleLinkList *head)
{
    SingleLinkList *p = head;
    int size = 0;
    while(p->next != NULL)
    {
        p = p->next;
        size++;
    }
    return size;
}

ListInsert() 插入一个元素
插入:先用插入节点的next指向当前节点的next,再用当前节点的next指向插入节点

//i为0表示从第1个位置插入
int ListInsert(SingleLinkList *head, int i, ElemType x)
{
    SingleLinkList *p = head;
    SingleLinkList *q = (SingleLinkList*)malloc(sizeof(SingleLinkList));
    q->data = x;
    int j = 0;
    while(p->next != NULL)
    {
        if (j == i) break;  //找到i位置对应的p
        p = p->next;
        j++;
    }
    if (j != i) //整个链表遍历完都没找到i的位置
    {
        printf("%s\n","插入位置错误!");
        return 0;
    }   
    
    q->next = p->next;
    p->next = q;
    return 1;
}

ListDelete() 删除一个元素
说明:循环条件添加p->next->next,避免p->next为NULL,且j等于i的情况,执行删除操作,程序奔溃

int ListDelete(SingleLinkList *head, int i, ElemType *x)
{
    SingleLinkList *p = head;
    if (p->next == NULL)
    {
        printf("%s\n", "链表为空,不能删除");
        return 0;
    }

    int j = 0;
    while(p->next != NULL && p->next->next != NULL)
    {
        if(j == i) break;
        j++;
        p = p->next;
    }   
    if (j != i)
    {
        printf("%s\n", "删除位置有错!");  
        return 0;   
    }

    SingleLinkList *s = p->next; *x = s->data;
    p->next = s->next;  //p->next = p->next->next
    free(s);
    return 1;
}

ListGet() 获取元素

//取数据元素
int ListGet(SingleLinkList *head, int i, ElemType *x)
{
    SingleLinkList *p = head;
    int j = 0;
    while(p->next != NULL && j < i)
    {
        p = p->next;
        j++;
    }
    if (j != i)
    {
        printf("%s\n", "取数据元素位置错误!");
        return 0;
    }
    *x = p->data;
    return 1;
}

ListDestroy() 销毁链表:从头往后销毁

void ListDestroy(SingleLinkList **head)
{
    SingleLinkList *p = *head;
    SingleLinkList *p1;

    while(p != NULL)
    {
        p1 = p;
        p = p->next;
        free(p1);
    }
    *head = NULL;
}

总结:
1、所有操作都需要while(p->next != null){}这个遍历,因为都需要从头往后找;
2、删除多了p->next->next != null 避免特殊情况;
3、初始化和销毁都需要对头指针本身进行操作,所以形参传入头指针的指针;其他操作都是直接传入头指针。

时间效率分析:
(1) 查找
因线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间复杂度为 O(n)。
(2) 插入和删除
操作本身是O(1),找下标O(n)。

优点:不需要预先设定链表长度。


例:
建立一个单链表,首先依次输入数据元素1,2,…,10,然后删除数据元素5,最后依次显示当前表中的数据元素。

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef int ElemType;
#include "SingleLinkList.h"
void main(void)
{
    SingleLinkList *head;
    int i, x, y, z;
    ListInstialize(&head);
    for(i=0;i<10;i++)
    {
        ListInsert(head, i, i + 1);
    }
    ListDelete(head, 10, &y);
    printf("删除的元素为:%d\n", y);
    for(i=0; i<ListLength(head);i++)
    {
        ListGet(head, i, &x);
        printf("%d ", x);
    }
    z = ListLength(head);
    printf("\n长度为:%d", z);
    ListDestroy(&head);
}

算法练习:
1、在递增的单链表中插入元素,保持链表的递增

//有序插入
void ListInsertOrderly(SingleLinkList *head, ElemType x) 
{
    SingleLinkList *pre = head;
    SingleLinkList *curr = head->next;
    SingleLinkList *q = (SingleLinkList*)malloc(sizeof(SingleLinkList));
    q->data = x;
    while(curr != NULL)
    {
        if(curr->data >= x) break;
        pre = curr;
        curr = curr->next;
    }

    pre->next = q;
    q->next = curr;
}

2、单链表la逆置后存到lb(头插法)

void Converse(SingleLinkList *la, SingleLinkList *lb)
{
    SingleLinkList *p, *q;
    p = la->next;
    while(p != NULL)
    {
        q = (SingleLinkList*)malloc(sizeof(SingleLinkList));
        q->data = p->data;
        
        q->next = lb->next;
        lb->next = q;
        
        p = p->next;
    }
} 

3、就地逆置(自身逆置)

void ConverseItself(SingleLinkList *head)
{
    //空表或只有一个元素直接退出 
    if(head->next == NULL || head->next->next == NULL) return;
    SingleLinkList *first, *mid, *last;
    first = head->next;
    mid = head->next;
    last = head->next->next;
    
    mid->next = NULL;
    mid = last;
    last = last->next;
    
    while(last != NULL)
    {
        mid->next = first;
        first = mid;
        mid = last;
        last = last->next;
    }
    mid->next = first;
    head->next = mid;
} 

相关文章

  • 数据结构与算法-C语言6-线性表之链式存储结构

    数据结构与算法-目录 1、线性表的链式存储结构 1.1、线性表链式存储结构定义 线性表的链式存储结构的特点是用一组...

  • 数据结构之有序线性表的链式存储结构

    之前写了线性表的顺序存储结构和有序线性表的顺序存储结构以及线性表的链式存储结构,今天接着写有序线性表的链式存储结 ...

  • 线性表的链式存储--单链表

    Java之线性表的链式存储——单链表 我们都知道,线性表的存储结构分为两种,顺序存储结构和链式存储结构,线性表的分...

  • 线性链表

    线性链表 线性表的顺序存储结构:顺序表线性表的链式存储结构:线性链表 线性表的链式存储所占存储空间大于顺序存储。 ...

  • 数据结构 线性表 链式存储结构

    本文主要介绍线性表的链式存储结构 为什么要使用链式存储结构? 首先我们知道,根据线性表的顺序存储结构,我们可以对顺...

  • 一、线性表

    一、线性表 线性表是一种抽象的数据类型,下面介绍几种具体的线性表存储结构(即物理结构):顺序、链式和静态链式。无论...

  • C++线性表的链式存储结构

    C++实现线性表的链式存储结构: 为了解决顺序存储不足:用线性表另外一种结构-链式存储。在顺序存储结构(数组描述)...

  • 数据结构学习第一弹 线性表(2)

    线性表的链式存储结构 前言: 采用链式存储结构的线性表称为链表,由n个结点链接而成特点: 对于顺序表的使用,我们一...

  • 第二讲-线性表

    第二讲 什么是线性表 由同类型数据元素构成的有序序列结构。线性表可以用顺序存储结构,也可以使用链式存储结构。链式结...

  • 数据结构和算法之一——线性表_2_顺序结构存储

    线性表存储结构分类线性表有两种物理存储结构:1)顺序存储结构;2)链式存储结构 顺序存储结构2.1定义:线性表的顺...

网友评论

      本文标题:线性表_链式结构

      本文链接:https://www.haomeiwen.com/subject/ztimcqtx.html