数据结构——单链表

单链表就是线性表的链式存储结构一般使用的是带头节点的链表,如图所示就是带头结点的单链表(我是用的语法是C++的)

带头结点的好处

  1. 有了头节点以后,链表中的首结点的插入和删除操作与其他结点一致。
  2. 无论单链表是否为空都一个头结点,也由此统一了空表和非空表的处理过程。

单链表基本操作

void InitList(LinkNode* &L)//初始化一个链表
void CreateList_Head(LinkList*& L, Elemtype a[], int n)//头插法创建链表
void CreateList_Tail(LinkList*& L, Elemtype a[], int n)//尾插法创建链表
void DestoryList(LinkNode* &L)//销毁一个链表
bool ListEmpty(LinkList* &L)//判断链表是否为空
int ListLength(LinkList* &L)//求出链表的长度
void DispList(LinkList* &L)//输出链表中的所有元素
bool Get_Elem_List(LinkList *&L,int i,Elemtype &e)//求链表中第i个位置的元素
int LocateList(LinkList *&L ,Elemtype e)//找到链表中第一个值为e的元素的位置
bool InsertList(LinkList *&L,int i,Elemtype e)//在第i个位置插入元素e
bool DeleteList(LinkList *& L ,int i)//删除第i个位置的元素

第一步是重中之重——创建单链表类型

typedef int Elemtype;
typedef struct List {
    Elemtype data;    //存放元素
    List* next;       //指向后继结点
}LinkList;            //单链表结点类型

其次就是初始化链表

创立一个头结点

void InitList(LinkList*& L)
{
    L = new LinkList;//创建头结点
    L->next = NULL;
}

建立单链表的秘籍1——头插法

注:头插法建立的单链表与实际输入的数据的次序是相反的

void CreateList_Head(LinkList*& L, Elemtype a[], int n)
{
    LinkList* p;
    L = new LinkList;//就是 L = (LinkList *)malloc(sizeof (LinkList));
    L->next = NULL;
    for (int i = 0; i < n; i++)
    {
        p = new LinkList;//与malloc作用一致
        p->data = a[i];
        p->next = L->next;
        L->next = p;
    }
}

秘籍2——尾插法

注:尾插法建立的链表与实际输入的数据的次序是一致的

void CreateList_Tail(LinkList*& L, Elemtype a[], int n)
{
    LinkList* p, * s;
    L = new LinkList;//malloc
    L->next = NULL;
    s = L;
    for (int i = 0; i < n; i++)
    {
        p = new LinkList;//malloc
        p->data = a[i];
        s->next = p;
        s = p;
    }
    s->next = NULL;
}

下面就是线性表的基本运算在单链表中的实现

~初始化在上文已经提及就不再赘述了

·销毁线性表

释放单链表L占用的内存空间——逐一释放全部结点的空间。

void DestoryList(LinkList*& L)
{
    LinkList* pre = L, * p = pre->next;    // pre 指向 p 的前驱节点
    while (p != NULL)                      //扫描单链表 L
    {
        delete pre;                        //释放 pre 结点 
        pre = p;                           //pre、p 同步后移一个结点
        p = pre->next;
    }
    delete pre;                            //循环结束时 p 为 NULL ,pre指向尾结点,释放它
}
//也可以用 free(); 来释放结点的内存

·判断链表是否为空

如果链表为返回 true 否则返回 false

bool ListEmpty(LinkList*& L)
{
    return (L->next == NULL);//头结点指向NULL说明没有元素存在于链表中
}

·求链表的长度

就是遍历一次链表返回链表的数据结点个数即他的长度

int ListLength(LinkList*& L)
{
    int len = 0;
    LinkList* p = L->next;
    while (p != NULL)            //遍历链表
    {
        len++;
        p = p->next;
    }
    return len;
}

·输出链表

逐一扫描单链表L的每个数据结点,并显示各个结点data域值

void DispList(LinkList*& L)
{
    LinkList* p = L->next;
    while (p != NULL)
    {
        cout << p -> data;
        p = p->next;
    }
    puts("");
}

·求出链表中的某个数据元素值

在链表上找到第i个节点,若存在第i个数据节点,则将其data域值返回

bool Get_Elem_List(LinkList*& L, int i, Elemtype& e)
{
    int cnt = 0;
    LinkList* p = L;
    if (i < 0) return false;
    while (cnt < i && p != NULL)
    {
        cnt++;
        p = p->next;
    }
    if (p == NULL) return false;
    else
    {
        e = p->data;
        return true;
    }
}

·按元素值查找

在单链表L中从头开始找第一个值域和e相等的结点,若这个结点存在,就返回其逻辑序号,否则返回-1.

int LocateList(LinkList*& L, Elemtype e)
{
    int pos = 1;              //p指向首结点,pos设置为1
    LinkList* p = L -> next;
    while (p != NULL && p->data != e )
    {
        pos++;
        p = p->next;
    }
    if (p == NULL)
        return 0;
    else
        return pos;
}

·插入数据元素

在单链表L中找到第 i - 1个结点,由p指向它。若存在这样的结点,将值为e的结点(s指向它)插入到p所指向的结点的后面

就是如图的操作 为了防止p的下一个结点的丢失,所以要按如上顺序进行操作

bool InsertList(LinkList*& L, int i, Elemtype e)
{
    int cnt = 0;
    LinkList* p = L, * s;
    if (i <= 0) return false;
    while (cnt < i - 1 && p != NULL)
    {
        cnt++;
        p = p->next;
    }
    if (p == NULL)
        return false;
    else
    {
        s = new LinkList;    //生成新的结点进行插入操作
        s->data = e;         //给新结点s赋值
        s->next = p->next;
        p->next = s;
        return true;
    }
}

 ·最后一个操作——删除数据元素

在链表中找到第i-1个结点,由p指向它。若存在就返回其域值并删除结点后返回true,否则返回false

 第二种方法是当你不需要知道删除的元素是什么的时候使用

bool DeleteList(LinkList*& L, int i)
{
    int j = 0;
    Elemtype e;
    LinkList* p = L, * q;
    if (i <= 0) return false;
    while (j < i - 1 && p != NULL)
    {
        j++;
        p = p->next;
    }
    if (p == NULL) return false;
    else
    {
        q = p->next;
        if (q == NULL)
            return false;
        e = q->data;
        p->next = q->next;
        delete q;
        return true;
    }
}

那么所有的操作到此就结束了//因为是C语言上的数据结构所以没有写C++的链表实现方式。

下面是一个 对学生数据类型的单链表实例

Code

#include <iostream>
#include <algorithm>
#include <string>
#define la_ji_lian_biao ios::sync_with_stdio(0) , cin.tie(0) , cout.tie(0);
using namespace std;
//typedef int Elemtype;
struct Stu {
    int id;
    string name;
    int score;
};
typedef Stu Elemtype;
typedef struct List {
    Elemtype data;
    List* next;
}LinkList;
//头插法创建链表
void CreateList_Head(LinkList*& L, Elemtype a[], int n)
{
    LinkList* p;
    L = new LinkList;
    L->next = NULL;
    for (int i = 0; i < n; i++)
    {
        p = new LinkList;
        p->data = a[i];
        p->next = L->next;
        L->next = p;
    }
}
//尾插法创建链表
void CreateList_Tail(LinkList*& L, Elemtype a[], int n)
{
    LinkList* p, * s;
    L = new LinkList;
    L->next = NULL;
    s = L;
    for (int i = 0; i < n; i++)
    {
        p = new LinkList;
        p->data = a[i];
        s->next = p;
        s = p;
    }
    s->next = NULL;
}
//初始化
void InitList(LinkList*& L)
{
    L = new LinkList;
    L->next = NULL;
}
//销毁链表
void DestoryList(LinkList*& L)
{
    LinkList* pre = L, * p = pre->next;
    while (p != NULL)
    {
        delete pre;
        pre = p;
        p = pre->next;
    }
    delete pre;
}
//判断链表是否为空
bool ListEmpty(LinkList*& L)
{
    return (L->next == NULL);
}
//求链表的长度
int ListLength(LinkList*& L)
{
    int len = 0;
    LinkList* p = L->next;
    while (p != NULL)
    {
        len++;
        p = p->next;
    }
    return len;
}
//输出线性表
void DispList(LinkList*& L)
{
    LinkList* p = L->next;
    cout << '\t' << '\t' << "学号" << '\t' << '\t' << "姓名" << '\t' << '\t' << "分数" << endl;
    while (p != NULL)
    {
        cout << '\t' << '\t' << p->data.id << '\t' << '\t' << p->data.name << '\t' << '\t' << p->data.score << endl;
        p = p->next;
    }
    puts("");
}
//求链表中第i个元素的值
bool Get_Elem_List(LinkList*& L, int i, Elemtype& e)
{
    int cnt = 0;
    LinkList* p = L;
    if (i < 0) return false;
    while (cnt < i && p != NULL)
    {
        cnt++;
        p = p->next;
    }
    if (p == NULL) return false;
    else
    {
        e = p->data;
        return true;
    }
}
//查找第一个学号为e的元素序号(位置)
int LocateList(LinkList*& L, Elemtype e)
{
    int pos = 0;
    LinkList* p = L;
    while (p != NULL && p->data.id != e.id )
    {
        pos++;
        p = p->next;
    }
    if (p == NULL)
        return 0;
    else
        return pos + 1;
}
//插入第i个元素
bool InsertList(LinkList*& L, int i, Elemtype e)
{
    int cnt = 0;
    LinkList* p = L, * s;
    if (i <= 0) return false;
    while (cnt < i - 1 && p != NULL)
    {
        cnt++;
        p = p->next;
    }
    if (p == NULL)
        return false;
    else
    {
        s = new LinkList;
        s->data = e;
        s->next = p->next;
        p->next = s;
        return true;
    }
}
//删除第i个元素
bool DeleteList(LinkList*& L, int i)
{
    int j = 0;
    Elemtype e;
    LinkList* p = L, * q;
    if (i <= 0) return false;
    while (j < i - 1 && p != NULL)
    {
        j++;
        p = p->next;
    }
    if (p == NULL) return false;
    else
    {
        q = p->next;
        if (q == NULL)
            return false;
        e = q->data;
        p->next = q->next;
        delete q;
        return true;
    }
}

int main()
{
    la_ji_lian_biao;
    LinkList* list;
    //初始化链表
    InitList(list);
    //判断是否为空
    if (ListEmpty(list)) puts("YES,list is empty!");
    else puts("NO,List is not empty!");
    puts("显示YES , 初始化成功 ,若输出NO,请重新运行程序");
    int n;
    Elemtype a[55];
    puts("请输入学生的数量 以及每个同学的学号、姓名、成绩");

    cin >> n;
    for (int i = 0; i < n; i++)    cin >> a[i].id >> a[i].name >> a[i].score;
    CreateList_Tail(list, a, n);

    cout << "链表list的长度为: " << ListLength(list) << endl;

    cout << "输出链表" << endl;
    DispList(list);

    cout << "请输入你要插入的同学的序号、学号、姓名、分数" << endl;
    int pos; Elemtype s;
    cin >> pos >> s.id >> s.name >> s.score;
    InsertList(list, pos, s);

    cout << "输出链表" << endl;
    DispList(list);

    cout << "请输入你要删除的同学的序号: "; int num; cin >> num;
    DeleteList(list, num);

    cout << "输出链表" << endl;
    DispList(list);
    
    cout << "查找第 x 个同学 并输出该同学的信息 " << endl;
    int x; Elemtype e;
    cin >> x;
    Get_Elem_List(list, x, e);
    cout << endl;
    cout << "该同学的学号为: " << e.id << endl << "该同学的姓名为: " << e.name << endl << "该同学的成绩为: " << e.score << endl;
   
    cout << "输出链表" << endl;
    DispList(list);

    cout << "删除链表";
    DestoryList(list);
    //if (ListEmpty(list)) cout << "删除成功" << endl;
    /*cout << "输出链表" << endl;
    DispList(list);*/
    return 0;
}

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

He_xj

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

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

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

打赏作者

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

抵扣说明:

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

余额充值