张小五学算法与数据结构第四天(上):线性表的链式存储结构

今天是元气满满的第四天,今天会有上下两篇,上篇写线性表的链式存储结构,下篇写有关栈的概述(emmmm现在已经很晚了,估计明天才会有下篇)。

一、单项链表的概述
将线性表L中各元素分布在存储器的不同存储快,称为结点,通过抵制或指针建立它们之间的联系,所得到的存储结构为链表结构。
结点data域存放数据元素ai,而next域是一个指针,指向ai的直接后继ai+1所在的结点。
二、单项链表的基本运算
单链表的基本运算主要包括单链表的建立和查找,插入和删除。
头文件linklist.h
/*
作者:张小五
时间:2018年1月28日

*/
#ifndef LINKLIST_H_
#define LINKLIST_H_

typedef struct node{ //结点类型
    int data; //结点的数据域
    struct node *next; //结点元素的后继指针域
}linkNode,*linkp;


void CreateList(linkp H); //建立单链表
void PrintList(linkp H);//打印单链表
linkp GetList(linkp H,int i);//根据序号查找
void InsertList(linkp H,int x ,int i);//插入元素
void DeleteList(linkp H,int i);//删除元素

#endif // LINKLIST_H_
linklist.c
/*
作者:张小五
时间:2018年1月28日

*/
#include "stdio.h"
#include "linklist.h"

//建立单链表
void CreateList(linkp H){
    int i=1;
    int a;
    linkp P,r;

    r=H; //首先定义一个数据区为空的头结点,将头结点指向第一个带有元素的结点
    printf("请输入链表第%d个元素,以-1结束:",i);
    scanf("%d",&a);
    while(a!=-1){
        P=(linkp)malloc(sizeof(linkNode));
        P->data = a;
        r->next = P; //指针指向下一个结点
        r = P;
        i++;
        printf("请输入链表第%d个元素,以-1结束:",i);
        scanf("%d",&a);
    }
    r->next=NULL; //循环到最后一个结点时,最后一个结点指向NULL,这是单项循环链表的特点

}
//打印单链表

void PrintList(linkp H){

    linkp P;
    P = H->next;
    printf("链表打印为:\n");
    while(P->next!=NULL){
            printf("%d ",P->data);
            P = P->next;
        }
    printf("%d ",P->data);
    printf("\n");
    }

//根据序号查找
linkp GetList(linkp H,int i){
    int j = -1;
    linkp P=H;
    if(i<0){
        return(NULL);
    }
    while(P->next&&j<i){
        P =P->next;
        j++;
    }
    if(i==j){
        return(P);
    }else{
        return(NULL);//查找失败
    }

}

//插入链表
void InsertList(linkp H,int x ,int i){
    linkp p,q;
    if(i==0){
        p=H;
    }else{
        p = GetList(H,i-1);//取结点ai-1
    }
    if(p==NULL){
        printf("位置不存在!\n");
    }else{
        q=(linkp)malloc(sizeof(linkNode));
        q->data = x; //存入数据
        q->next = p->next;
        p->next = q;
    }

}
//删除结点
void DeleteList(linkp H,int i){
    linkp p,q;
    if(i==0){
        p=H;
    }else{
        p = GetList(H,i-1);//取结点ai-1
    }
    if(p!=NULL&&p->next!=NULL){
        q = p->next;
        p->next = q->next;
        free(q);
    }else{
        printf("删除失败!\n");
    }
}
main.c

/*
作者:张小五
时间:2018年1月28日

*/
#include "stdio.h"
#include "linklist.h"
#include "linklist.c"
int main(int argc,char *argv[]){
    linkp H;
    H =(linkp)malloc(sizeof(linkNode));
    H->next = NULL;
    CreateList(H);
    PrintList(H);
    /*int i;
    linkp temp;
    printf("请输入要查找的位置:");
    scanf("%d",&i);
    temp = GetList(H ,i-1);
    if(temp!=NULL){
        printf("你要查找的数值是%d\n",temp->data);
    }else{
        printf("你要查找的位置不存在!\n");
    }*/
    /*int x,i;
    printf("请输入要插入的数据和位置:\n");
    scanf("%d %d",&x,&i);
    InsertList(H,x,i-1);*/

    int i ;
    printf("请输入要删除的位置:");
    scanf("%d",&i);
    DeleteList(H,i-1);
    PrintList(H);

    return 0;
}
运行结果(只显示删除的运行结果):

三、单项链表的扩展运算
有关单项列表的扩展运算无非是列表的倒置以及合并,首先来看链表的倒置:
//倒置链表
void L1n_Ln1(linkp H){
    linkp p,q;
    p = H->next; //将头结点复制给p然后将头结点置空
    H->next = NULL;
    while(p!=NULL){
        q = p;//复制一份结点,让结点q代替结点p进行链接
        p = p->next;
        q->next = H->next;
        H->next = q;//将结点插入到头结点中

    }
}
结果显而易见:


两个有序链表之间的有序合并:例如一个链表L1=(1,3,5),另一个链表L2=(2,4)则合成新链表L=(1,2,3,4,5)代码就不在这里进行展示了,但是说一下原理。
首先用他们只需一个头结点就可以了,所以可以释放一个头结点,用一个复制的结点来代替头结点,然后两个链表的元素开始比较大小,较小的这个放到新的头结点之后,然后较小的那列结点后移,然后再次比较,直至两个链表都为空停止。如图:

四、单项循环链表的概述及运算
单项循环链表是单链表的一种改进,若将单链表的首尾结构相连,便构成了单项循环链表结构,这样,若运算频繁在为不运行,可设一表尾指针R(H就可以省去了)。这样,为获得表位an-1,取R->data即可,不需要遍历到表尾,而取a0的运算为(R->NEXT->NEXT)->data
运算方式也和单向链表大致相同,唯一不同的计算为两链表进行简单连接,设ra和rb分别为两单项循环链表尾指针。
这样就可以完成AB的简单链接。
五、双向循环链表的概述和计算
在单链表L中,查找ai的后继next(L,ai),耗时仅为O(1),因为取ai的后继指针酒可以。但是查找ai的直接前驱Piroi(L,ai),则需要从链表头指针开始,他的时间复杂度是O(n)。另外,若链表中有一指针被破坏,则整个链表脱节。这是单链表的不足,为此,引入双向链表。先定义双向链表中的结点:

那么双向循环链表和单向链表的计算又会有差异,我就不贴源代码在这里了,但是我会把算法放在这里,有时间的话我会写一个练习篇放在那里面:
下面是双向循环链表的插入算法:

下面是双向循环链表的删除算法:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张小五丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值