线性表之链表实现:单向链表、循环链表、双向链表

余生长醉 提交于 2019-12-22 05:34:31

线性表

单向链表实现:

  • 优点:便于插入和删除
  • 缺点:查找数据需要遍历

声明

  • 一个数据+一个指针
typedef struct LNode *List;
struct LNode
{
    int Data;
    List next;
};

求表长

  • 遍历表,当指向节点的指针为NULL时停止
int Length(List PtrL)
{
    List p = PtrL;
    int j = 0;
    while (p)
    {
        p = p->next;
        j++;
    }
    return j;
}

查找数据

  • 当指针不为NULL或者未找到数据时,继续循环

按值查找

List Find(int X, List PtrL)
{
    List p = PtrL;
    while (p!=NULL && p->Data != X)p = p->next;
    return p;
}

按序号查找

List FindKth(int K, List PtrL)
{
    List p = PtrL;
    int i = 1;
    while (p != NULL&&i < K)
    {
        p = p->next;
        i++;
    }
    if (i == K)return p;
    else return NULL;
}

插入数据

  • 当插在第一个位置时:创建节点,让该节点直接指向头结点。
  • 当插在第i个位置时:创建节点,让该节点指向该位置的后一个节点,再让这个位置的节点指向插入的节点。
List Insert(int X, int i, List PtrL)
{
    List p, s;
    if (i == 1)
    {
        s = (List)malloc(sizeof(struct LNode));
        s->Data = X;
        s->next = PtrL;
        return s;
    }
    p = FindKth(i-1, PtrL);
    if (p == NULL)
    {
        printf("Error!");
        return NULL;
    }
    else
    {
        s = (List)malloc(sizeof(struct LNode));
        s->Data = X;
        s->next = p->next;
        p->Data = s;
        return PtrL;
    }
}

删除数据

  • 当删除头结点时,用一个临时指针指向头结点,将第二个结点当作头结点,再释放原头结点的内存。
  • 当删除中间结点时,用一个临时指针指向该中间结点,该位置结点指向下一个结点,再释放要删除的结点的内存。
  • p指针指向要删除结点的前一个结点,要注意指向的结点是否为NULL;
List Delete(int i,List PtrL)
{
    List p, s;
    if (i == 1)
    {
        s = PtrL;
        if (PtrL != NULL)PtrL = PtrL->next;
        else return NULL;
        free(s);
        return PtrL;
    }
    p = FindKth(i - 1, PtrL);
    if (p == NULL)
    {
        printf("The %d node is not exited!",i-1);
        return NULL;
        }
    else if (p->next == NULL)
    {
        printf("The %d node is not exited!", i);
        return NULL;
    }
    else
    {
        s = p->next;
        p->next = s->next;
        free(s);
        return PtrL;
    }
}

输出数据

void Print(List PtrL)
{
    while (PtrL != NULL)
    {
        printf("%d ", PtrL->Data);
        PtrL = PtrL->next;
    }
    return;
}

注意

  • 自定义的线性表并不一定更要按标准,顾名思义,自定义线性表就是自定义,完全可以自己大胆改变线性表的内容。

循环链表

  • 最后一个元素不指向空指针而是指向头节点,形成一个环,这样首尾相接的链表就称为循环链表。

优点

  • 查找第一个元素和最后一个元素花费时间降为O(1)。

改变

  • 最后一个元素指向头结点。与next原先指向空指针的操作均要改为头结点。

双向循环链表

  • 在结点中同时储存两个指针,分别用于指向前驱和后继,同时最后一个指针指向头结点。

优点

  • 便于查找前驱后继。
  • 查找第一个元素和最后一个元素花费时间降为O(1)。
  • 便于反向遍历。

实现代码

#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct node Node;
typedef struct node *link;

struct node
{
    int element;
    link left;
    link right;
};

typedef struct dlist *List;
typedef struct dlist Dlist;

typedef struct dlist
{
    int n;
    link leftEnd, rightEnd;
    link header;
};
link NewNode()
{
    link L;
    L = (link)malloc(sizeof(Node));
    return L;
}
List ListInit()
{
    node* y;
    List L = (List)malloc(sizeof(dlist));
    y = NewNode();
    y->left = y;
    y->right = y;
    L->header = y;
    L->n = 0;
    return L;
}
int ListRetrieve(int k, List L)
{
    int i = 1;
    link p;
    p = L->header->right;
    if (k<1 || k>L->n)printf("out of bounds");
    while (i < k) { p = p->right; i++; }
    return p->element;
}
int ListLocate(int x, List L)
{
    int i = 0;
    link p;
    p = L->header->right;
    L->header->element = x;
    while (p->element!=x) { p = p->right; i++; }
    return ((p == L->header) ? 0 : i);
}
void ListInsert(int x, int k, List L)
{
    int i = 0;
    link p, y;
    p = L->header;
    for (i = 1; i < k; i++) { p = p->right; }
    y = NewNode();
    y->element = x;
    y->left = p;
    y->right = p->right;
    p->right->left = y;
    p->right = y;
    L->n++;
    return;
}
int ListDelete(int k, List L)
{
    int x;
    link p;
    if (k<1 || k>L->n)printf("out of bounds");
    p = L->header;
    int i = 1;
    for (i = 1; i < k; i++)p = p->right;
    p->left->right = p->right;
    p->right = p->left;
    x = p->element;
    free(p);
    return x;
}
void PrintList(List L)
{
    link p;
    for (p = L->header->right; p != L->header; p = p->right)
        printf("%d ",p->element);
    return;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!