线性表:链式储存结构(单链表)

一、定义

每个元素(结点)分为数据域和指针域,数据域储存数据信息,指针域储存指向后继元素的指针。所以不用把所有元素像顺序结构一样连续储存,因为有指针域,所以我们就能将数据链接在一起。
在这里插入图片描述

二、特点

(1)、指向第一个节点的指针叫头指针,最后一个结点指针域为空,通常用NULL表示。
在这里插入图片描述(2)、有时为了更好地操作链表,会在第一个结点前设置一个头结点,该结点数据域为空(有时存放链表长度),指针域指向第一个结点,此时头指针指向头结点。

三、储存结构表示
typedef int ElemType;
typedef struct Node
{
    ElemType data;//数据域
    struct Node *next;//指针域
}Node,*LinkList;
四、其他操作(针对带头结点单链表)

1、整表创建
(1)、头插法
特点:始终让新结点在第一个结点的位置

void CreateListHead(LinkList *L,int n)
{
    LinkList p;//插入结点p
    ElemType data;//插入结点p的数据
    *L=(LinkList)malloc(sizeof(Node));//给头结点分配内存
    (*L)->next=NULL;//此时只有一个头结点,所以头结点指针域为空
    for(int i=0;i<n;i++)
    {
        cin>>data;
        p=(LinkList)malloc(sizeof(Node));//给插入结点p分配内存
        p->data=data;
        //头插法
        p->next=(*L)->next;
        (*L)->next=p;
    }
}

(2)、尾插法
特点:新结点插在最后一个结点后面

void CreateListTail(LinkList *L,int n)
{
    LinkList p,r;//定义插入结点p和尾部指针
    ElemType data;
    *L=(LinkList)malloc(sizeof(Node));//为头结点分配内存
    (*L)->next=NULL;//此时只有一个头结点,所以头结点指针域为空
    r=*L;//使尾部指针指向尾部结点
    for(int i=0;i<n;i++)
    {
        p=(LinkList)malloc(sizeof(Node));//给插入结点p分配内存
        cin>>data;
        p->data=data;
        r->next=p;
        r=p;//始终让尾部指针指向尾部结点
    }
    r->next=NULL;//让尾部结点指针域为空,因为它无后继结点
}

2、销毁链表

void ClearList(LinkList *L)
{
    LinkList p,q;//创建指针p,q;
    p=(*L)->next;//p始终指向要销毁的结点
    while(p)
    {
        q=p->next;//q始终保存要销毁结点的后继结点
        free(p);
        p=q;
    }
    (*L)->next=NULL;//头结点指针域为空
}

3、读取链表

int getElem(LinkList L,int i,ElemType *e)
{
    int j=1;//定义一个计数器
    LinkList p=L->next;//使指针p指向第一个结点
    while(p&&j<i)
    {
        p=p->next;//指针指向下一个结点
        ++j;
    }
    if(!p||j>i)
        return 0;
    *e=p->data;
    return 1;
}

4、链表的插入

//在第i个位置前插入新结点
int ListInsert(LinkList *L,int i,ElemType e)
{
    int j=1;//定义一个计数器j
    LinkList p=*L;//让指针p指向头结点
    LinkList s;//要插入的新结点s
    while(p&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i)
        return 0;
    s=(LinkList)malloc(sizeof(Node));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return 1;
}

5、删除链表结点

int ListDelete(LinkList *L,int i,ElemType *e)
{
    int j=1;//定义一个计数器j
    LinkList p=(*L)->next;//使指针p指向第一个结点
    LinkList q;
    while(p&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i)
        return 0;
    *e=p->data;
    q=p->next;//使指针q指向要删除结点的下一个结点
    p->next=q->next;
    free(p);
    return 1;
}
五、链表与数组优缺点

(1)、用数组进行插入删除时,时间复杂度为o(n),用链表进行插入删除时,时间复杂度为o(1),所以要进行大量插入删除时,最好使用链式结构。
(2)、查找时,数组时间复杂度为o(1),链表时间复杂度为o(n),所以要进行频繁查找时,最好使用数组结构。
(3)、线性表元素变化较大或未知数量最好使用链式结构节省空间。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链式存储的单链表是一种常见的数据结构,以下是C语言实现单链表的插入、删除、查找、求表长、置逆以及有序单链表的合并算法的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义单链表节点结构体 typedef struct Node { int data; struct Node* next; } Node; // 在单链表中插入一个节点 void insertNode(Node** head, int value) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = value; newNode->next = *head; *head = newNode; } // 从单链表中删除一个节点 void deleteNode(Node** head, int value) { Node* curr = *head; Node* prev = NULL; while (curr != NULL && curr->data != value) { prev = curr; curr = curr->next; } if (curr == NULL) { printf("Node not found.\n"); return; } if (prev == NULL) { *head = curr->next; } else { prev->next = curr->next; } free(curr); } // 在单链表中查找一个节点 Node* searchNode(Node* head, int value) { Node* curr = head; while (curr != NULL) { if (curr->data == value) { return curr; } curr = curr->next; } return NULL; } // 求单链表的长度 int getLength(Node* head) { int length = 0; Node* curr = head; while (curr != NULL) { length++; curr = curr->next; } return length; } // 将单链表置逆 void reverseList(Node** head) { Node* prev = NULL; Node* curr = *head; Node* next = NULL; while (curr != NULL) { next = curr->next; curr->next = prev; prev = curr; curr = next; } *head = prev; } // 合并两个有序单链表 Node* mergeLists(Node* list1, Node* list2) { Node* mergedList = NULL; Node** tail = &mergedList; while (list1 != NULL && list2 != NULL) { if (list1->data <= list2->data) { *tail = list1; list1 = list1->next; } else { *tail = list2; list2 = list2->next; } tail = &((*tail)->next); } if (list1 != NULL) { *tail = list1; } else { *tail = list2; } return mergedList; } // 打印单链表中的元素 void printList(Node* head) { Node* curr = head; while (curr != NULL) { printf("%d ", curr->data); curr = curr->next; } printf("\n"); } // 析构单链表 void destroyList(Node** head) { Node* curr = *head; Node* next; while (curr != NULL) { next = curr->next; free(curr); curr = next; } *head = NULL; } int main() { Node* head = NULL; // 插入节点 insertNode(&head, 3); insertNode(&head, 2); insertNode(&head, 1); // 打印链表 printf("Linked List: "); printList(head); // 查找节点 Node* node = searchNode(head, 2); if (node != NULL) { printf("Found node with value %d\n", node->data); } else { printf("Node not found.\n"); } // 删除节点 deleteNode(&head, 2); // 打印链表 printf("Linked List after deletion: "); printList(head); // 求链表长度 int length = getLength(head); printf("Length of Linked List: %d\n", length); // 置逆链表 reverseList(&head); // 打印链表 printf("Reversed Linked List: "); printList(head); // 析构链表 destroyList(&head); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值