数据结构严薇敏——线性表的链式存储(C语言)

线性表的链式存储结构特点使用一组任意的存储单元存储线性表的数据元素(这组存储单元地址可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素与其前后的数据元素的逻辑关系,除了需要存储本身的数据信息之外,还需要存储一个指针来指向当前位置的下一个数据元素的位置。于是需要定义一个数据类型,里面包含两个域,数据域和指针域,我们称之为结点。

其数据类型(结点)定义方式如下:

typedef struct LNode
{
    int data;                   //数据域
    struct LNode *next;         //指针域
}LNode;

我们需要做的就是对上面这个结点进行一系列的操作(增,删,改,查,等)。

这里我们要特别分清楚头指针、头结点、首元结点这三个概念。

头指针:他指向表中的第一个节点,由它的起始位置来构造这一串链表,每次操作链表都需要找到头指针才能找到对应的链表。所以头指针是必不可少的。

头结点:它的位置在头指针之后,第一个储存数据元素结点(图中a1的位置)之前。头结点的数据域可以不存储任何的数据,也可以存储单链表当前的长度之类的信息(以下的代码就是),他的指针域指向第一个结点(a1)。一个单链表中可以没有头结点,但是不可以没有头指针。设置头结点的作用是插入(第一个结点之前)和删除首元结点时不用进行特殊处理。

首元结点:第一个存储数据元素的结点(图中的a1)。

下面是创建有头结点和无头结点链表的代码,对比一下。

有头结点:

LinkList *CreateList_L(int n)      //创建
{
    int i;
    LNode *p;
    LinkList *L = (LinkList *)malloc(sizeof(LinkList));   //头指针
    L -> size = 0;
    L->head = (LNode *)malloc(sizeof(LNode));         //头结点
    L->head->data = 0;
    L->head->next = NULL;
    return L;
}

无头结点:

LNode *CreateNoheadList_L(int n)
{
    int i;
    LNode *q;
    LNode *L = (LNode *)malloc(sizeof(LNode));
    L->data = n;
    L->next = NULL;
    return L;
}

下面是完整的单链表创建及操作的完整代码:

头文件#include"Link_List.h"

#ifndef LINK_LIST_H_INCLUDED
#define LINK_LIST_H_INCLUDED

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode;
typedef struct LinkList
{
   LNode *head;
   int size;
}LinkList;

LinkList *CreateList_L(int n)      //创建
{
    int i;
    LNode *p;
    LinkList *L = (LinkList *)malloc(sizeof(LinkList));
    L -> size = 0;
    L->head = (LNode *)malloc(sizeof(LNode));
    L->head->data = 0;
    L->head->next = NULL;

    for( i = 0;i < n;i++)
    {
        p = (LNode *)malloc(sizeof(LNode));
        scanf("%d",&p -> data);
        p -> next = L -> head-> next;
        L -> head -> next = p;
    }
    L->size = n;
    printf("链表创建成功!\n");
    return L;
}
void DestoryList_L(LinkList *L)     //销毁
{
    if(L == NULL)
        return;
    LNode *current = L->head;
    LNode *Next;
    while( current != NULL)
    {
        Next = current ->next;
        free(current);
        current = Next;
    }
    L ->size = 0;
    free(L);
    printf("链表销毁成功!\n");
}
void InsertList_L(LinkList *L, int pos, int e)  //插入元素
{
    if( L == NULL )
        return;
    if( pos < 0 || pos > L->size)
    {
        pos = L->size;
    }

    LNode *newnode = (LNode *)malloc(sizeof(LNode));
    newnode->data = e;
    newnode->next = NULL;
    LNode *current = L->head;
    int i;
    for( i = 0; i < pos; i++ )
    {
       current = current ->next;
    }
    newnode ->next = current ->next;
    current ->next = newnode;
    L ->size++;
}
void DeleteListByPos_L(LinkList *L, int pos)   //按位置进行删除元素
{
    if( L == NULL)
        return;
    if( pos < 0 || pos > L->size )
    {
        printf("你输入的位置不合法,请重新输入!\n");
        return;
    }
    int i;
    LNode *Next;
    LNode *current = L->head;
    for( i = 0;  i < pos; i++ )
    {
        current = current ->next;
    }
    Next = current ->next;
    current ->next = current ->next->next;
    free(Next);                           //后释放结点
    L->size--;
}
void DeleteListByValue_L(LinkList *L, char e)
{
    if( L == NULL)
        return;
    int i = 0 ;
    LNode *current = L->head;
    while(current ->next->data != e)
    {
        current = current ->next;
        i++;
        if(i >= L->size)
        {
            printf("您要删除的元素不存在,请重新输入!");
            break;
        }
    }
    LNode *Next = current ->next;
    current->next = current ->next->next;
    free(Next);
    L->size--;
}

int  FindList_L(LinkList *L,char e)            //查找
{
      int i = 1;
      LNode *current = L->head->next;
      while( current != NULL )
      {
          if(current ->data == e) break;
          if( i >= L->size)
          {
              printf("您要查找的元素不存在,请重新输入!");
              return -1;
          }
          current = current->next;
          i++;
      }
      printf("您要查找的元素位于第%d位!\n",i);
      return i;
}

void PrintList_L(LinkList *L)           //打印
{

    if(L == NULL)
    {
       printf("链表为空!");
       return;
    }
    LNode *current = L->head->next;
    while( current != NULL)
    {
        printf("%d\t",current -> data);
        current = current -> next;
    }
    printf("\n");
}
int SizeList_L(LinkList *L)
{
   return L->size;
}
//删除表中所有值大于mink且效益maxk的元素,同时释放删除节点的空间
//当时调试错误在于没有明确指针的位置,利用画图来帮助理解
void DeleteListBetween(LinkList *L,int mink,int maxk)
{
    if( L == NULL)
    {
        printf("链表为空!");
        return;
    }
    LNode *current = L->head;
    LNode *Next;
    while(current ->next != NULL)
    {
        if( current->next->data > mink && current->next->data < maxk)
        {
            Next = current->next;
            current ->next = current ->next->next;

            free(Next);
            L->size--;
            //current = current ->next;
        }
        else
        {
          current = current->next;
        }

    }
    printf("删除并释放节点成功!\n");
}
//删除表中所有值相同的多余元素
void DeleteListSameNode(LinkList *L)
{
    if( L == NULL)
    {
        printf("链表为空!\n");
        return;
    }
    LNode *current  = L->head;
    LNode *Next,*pre;
    while(current ->next != NULL)
    {
        pre = current;
        if(current->next->data == pre->data)
        {
            Next = current->next;
            current ->next = current ->next->next;

            free(Next);
            L->size--;
        }
        else
        {
            current = current ->next;
        }
    }
    printf("删除相同的值成功!\n");
}
//将链表逆置
void ReverseList_L(LinkList *L)
{
    if( L == NULL)
    {
        printf("链表为空!\n");
        return;
    }
    LNode *current = L ->head->next;
    LNode *Next;
    L ->head->next = NULL;
    while(current != NULL)
    {
        Next = current;
        current = current->next;
        Next->next = L->head->next;
        L->head->next = Next;
    }
    printf("链表逆置成功!\n");
}
//合并两个单链表并用La或Lb作为存储空间,插入位置是La链表的尾端
void MergeList_L(LinkList *La, LinkList *Lb)
{
    //int size = 0;
    if(La == NULL || Lb == NULL)
    {
        printf("其中有链表为空,不需要合并!");
        return;
    }
    LNode *pa = La->head,*pb = Lb->head;
    while(pa->next!= NULL)
    {
        if(pa->next != NULL)
            pa = pa->next;
    }
    while(pb->next != NULL)
        pb = pb->next;
    pb->next = pa->next;
    pa->next = Lb->head->next;
    La->size = La->size + Lb->size;
    //DestoryList_L(Lb);
    //printf("链表合并完成,当前链表的长度为%d:\n",size);
}
#endif // LINK_LIST_H_INCLUDED

头文件#include"NoHeadLink_List.h"

#ifndef NOHEADLINK_LIST_H_INCLUDED
#define NOHEADLINK_LIST_H_INCLUDED

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include "Link_List.h"

LNode *CreateNoheadList_L(int n)
{
    int i;
    LNode *q;
    LNode *L = (LNode *)malloc(sizeof(LNode));
    L->data = n;
    L->next = NULL;
    q = L;
    for( i = 0; i < n;i++ )
    {
        LNode *p = (LNode *)malloc(sizeof(LNode));
        scanf("%d",&p->data);
        q->next = p;
        p->next = NULL;
        q = p;
    }
    printf("无头链表创建成功!\n");
    return L;
}
void PrintNoheadList_L(LNode *L)
{
    if( L == NULL)
    {
        printf("此链表为空!");
        return;
    }
    LNode *current = L ->next;
    while(current != NULL)
    {
        printf("%d\t",current->data);
        current = current ->next;
    }
    printf("\n无头链表输出成功!\n");
}
int NoheadSize(LNode *L)
{
    return L->data;
}
#endif // NOHEADLINK_LIST_H_INCLUDED

主函数main

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include"Link_List.h"
#include"NoHeadLink_List.h"

void testMerge()                //测试合并
{
    LinkList *La = CreateList_L(5);
    PrintList_L(La);
    printf("----------------------------------------\n ");
    LinkList *Lb = CreateList_L(5);
    PrintList_L(Lb);
    MergeList_L(La,Lb);
    printf("=================合并之后的链表=========================\n\n");
    PrintList_L(La);
    printf("\n当前链表的长度为:%d\n",SizeList_L(La));
}

void testRevrese()                //测试逆转
{
    LinkList *L = CreateList_L(5);
    printf("----------逆转前---------\n");
    PrintList_L(L);
    printf("\n当前链表的长度为:%d\n",SizeList_L(L));
    ReverseList_L(L);
    printf("----------逆转后---------\n");
    PrintList_L(L);
    printf("\n当前链表的长度为:%d\n",SizeList_L(L));

}

void  testSameNode()             //测试删除相同的结点并进行释放
{
    LinkList *L = CreateList_L(5);
    printf("----------删除前---------\n");
    PrintList_L(L);
    printf("\n当前链表的长度为:%d\n",SizeList_L(L));
    DeleteListSameNode(L);
    printf("----------删除后---------\n");
    PrintList_L(L);
    printf("\n当前链表的长度为:%d\n",SizeList_L(L));
}

void testBetween()                  //测试删除中间的值
{
    LinkList *L = CreateList_L(5);
    printf("----------删除前---------\n");
    PrintList_L(L);
    DeleteListBetween(L,0,6);
    printf("----------删除后---------\n");
    PrintList_L(L);
    printf("\n当前链表的长度为:%d\n",SizeList_L(L));
}

void testwWT()                        //测试无头链表
{
    LNode *L = CreateNoheadList_L(5);
    PrintNoheadList_L(L);
    printf("当前无头链表的长度为:%d\n",NoheadSize(L));
}

void test()                         //测试带头链表
{
    LinkList *L = CreateList_L(5);

    PrintList_L(L);
    printf("---------插入后-------------\n");
    InsertList_L(L,3,6);
    PrintList_L(L);
    InsertList_L(L,2,1);
    PrintList_L(L);
    system("pause");
    printf("---------按值删除后-------------\n");
    DeleteListByValue_L(L,1);
    PrintList_L(L);
    printf("---------按位置删除后-------------\n");
    DeleteListByPos_L(L,2);
    PrintList_L(L);
    printf("---------查找结果-------------\n");
    FindList_L(L,5);
    DestoryList_L(L);
    printf("\n当前链表的长度为:%d\n",SizeList_L(L));
}
int main()
{
    testMerge();
    //testRevrese();
    //testSameNode();
    //testBetween();
    //testwWT();
    //test();
    system("pause");
    return 0;
}

注:部分代码在程序测试时为了方便其他函数进行测试已经注释掉,如需参考请略加修改。

 

1.1 数组和字符串 2 1.1.1 一维数组的倒置 2 范例1-1 一维数组的倒置 2 ∷相关函数:fun函数 1.1.2 一维数组应用 3 范例1-2 一维数组应用 3 1.1.3 一维数组的高级应用 5 范例1-3 一维数组的高级应用 5 1.1.4 显示杨辉三角 7 范例1-4 显示杨辉三角 7 ∷相关函数:c函数 8 1.1.5 魔方阵 9 范例1-5 魔方阵 9 1.1.6 三维数组的表示 14 范例1-6 三维数组的表示 14 ∷相关函数:InitArray函数 1.1.7 多项式的数组表示 17 范例1-7 多项式数组的表示 17 1.1.8 查找矩阵的马鞍点 19 范例1-8 查找矩阵的马鞍点 19 ∷相关函数:Get_Saddle函数 1.1.9 对角矩阵建立 21 范例1-9 对角矩阵建立 21 ∷相关函数:Store函数 1.1.10 三对角矩阵的建立 22 范例1-10 三对角矩阵的建立 22 ∷相关函数:Store函数 1.1.11 三角矩阵建立 24 范例1-11 三角矩阵建立 24 ∷相关函数:Store函数 1.1.12 对称矩阵的建立 25 范例1-12 对称矩阵的建立 25 ∷相关函数:store函数 1.1.13 字符串长度的计算 28 范例1-13 字符串长度的计算 28 ∷相关函数:strlen函数 1.1.14 字符串的复制 29 范例1-14 字符串的复制 29 ∷相关函数:strcpy函数 1.1.15 字符串的替换 31 范例1-15 字符串的替换 31 ∷相关函数:strrep函数 1.1.16 字符串的删除 33 范例1-16 字符串的删除 33 ∷相关函数:strdel函数 1.1.17 字符串的比较 35 范例1-17 字符串的比较 35 ∷相关函数:strcmp函数 1.1.18 字符串的抽取 36 范例1-18 字符串的抽取 36 ∷相关函数:substr函数 1.1.19 字符串的分割 38 范例1-19 字符串的分割 38 ∷相关函数:partition函数 1.1.20 字符串的插入 40 范例1-20 字符串的插入 40 ∷相关函数:insert函数 1.1.21 字符串的匹配 42 范例1-21 字符串的匹配 42 ∷相关函数:nfind函数 1.1.22 字符串的合并 43 范例1-22 字符串的合并 43 ∷相关函数:catstr函数 1.1.23 文本编辑 45 范例1-23 文本编辑 45 ∷相关函数:StrAssign函数 1.2 栈和队列 54 1.2.1 用数组仿真堆栈 54 范例1-24 用数组仿真堆栈 54 ∷相关函数:push函数 pop函数 1.2.2 用链表仿真堆栈 57 范例1-25 用链表仿真堆栈 57 ∷相关函数:push函数 pop函数 1.2.3 顺序栈公用 59 范例1-26 顺序栈公用 59 ∷相关函数:push函数 pop函数 1.2.4 进制转换问题 61 范例1-27 进制转换问题 61 ∷相关函数:MultiBaseOutput函数 1.2.5 顺序队列操作 64 范例1-28 顺序队列操作 64 ∷相关函数:push函数 pop函数 1.2.6 循环队列 66 范例1-29 循环队列 66 ∷相关函数:EnQueue函数 DeQueue函数 1.2.7 链队列的入队、出队 69 范例1-30 链队列入队、出队 69 ∷相关函数:push函数 pop函数 1.2.8 舞伴问题 71 范例1-31 舞伴问题 71 ∷相关函数:EnQueue函数 DeQueue函数 DancePartner函数 1.3 链表 75 1.3.1 头插法建立单链表 75 范例1-32 头插法建立单链表 75 ∷相关函数:createlist函数 1.3.2 限制链表长度建立单链表 77 范例1-33 限制链表长度建立长单链表 77 ∷相关函数:createlist函数 1.3.3 尾插法建立单链表 79 范例1-34 尾插法建立单链表 79 ∷相关函数:createlist函数 1.3.4 按序号查找单链表 80 范例1-35 按序号查找单链表 80 ∷相关函数:getnode函数 1.3.5 按值查找单链表 82 范例1-36 按值查找单链表 82 ∷相关函数:locatenode函数 1.3.6 链表的插入 84 范例1-37 链表的插入 84 ∷相关函数:insertnode函数 1.3.7 链表的删除 86 范例1-38 链表的删除 86 ∷相关函数:deletelist函数 1.3.8 归并两个单链表 88 范例1-39 归并两个单链表 88 ∷相关函数:concatenate函数 1.3.9 动态堆栈 90 范例1-40
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值