2.线性表的链式存储结构-----单链表(上篇,C++版本)

主要介绍了单链表的基本概念和相关操作,由于篇幅太长,本文只给出了C++版本的程序,下篇将给出完整的C语言版本的程序,这两个不同版本实现的功能完全相同。

 

目录

1.单链表的基本概念

2.单链表的基本操作

3.单链表编程实现----C++

4.单链表编程实现----C语言

5.实验结果


1.单链表的基本概念

(1)单链表:当链表中的每个结点只含有一个指针域时,称为单链表。

(2)头指针:如上图所示,链表中第一个结点的存储位置叫做头指针。

(3)头结点:头结点是放在第一个元素结点之前的结点,头结点不是链表中的必须元素,其数据域一般无意义,(有些情况下会存放链表的长度,或用作监视哨等),本文的头结点存放了链表的长度。有了头结点后,对在第一个元素结点前插入结点和删除第一个结点,其操作与对其它结点的操作统一了。

(4)首元结点:就是第一个元素的结点,它是头结点后边的第一个结点。

2.单链表的基本操作

(1)初始化:给链表添加一个头结点。

(2)逆置链表:将单链表所有元素逆置。

(3)链表遍历:打印出链表的长度,并按顺序打印所有元素。

(4)查找:获取指定位置的元素。

(5)元素插入:在指定位置插入元素。

(6)元素删除:删除指定位置的元素。

(7)删除链表:将链表删除。

(8)头插法创建链表:用头插法插入一系列元素,创建链表。

(9)尾插法创建链表:用尾插法插入一系列元素,创建链表。

这些操作中,链表逆置具有一定的难度,其基本的设计思想是:将以前的旧链表中的每个元素从旧链表中删除,并用头插法插入新的链表中。

3.单链表编程实现----C++

(1)类的头文件 linklist.h

#ifndef LIST_H
#define LIST_H

typedef int ElemType;

struct Node
{
    ElemType data;
    struct Node *next;
};

class List
{
public:
    List();//链表,可以删除所有动态节点
    ~List();//删除全部节点
    void traverseList();//遍历
    bool ListInsert(int i,ElemType d);//在第i个节点位置插入元素d
    void CreateListHead(int n);//头插法插入
    void CreateListEnd(int n);//尾插法插入
    void Reverse();//逆置单链表
    bool ListDelete(int i,ElemType& e);//删除第i个元素
    bool GetElem(int i,ElemType& e);//获取第i个节点位置的元素,并且返回给e

private:
    Node *head;//存放头结点
};

#endif // LIST_H

(2)类的源文件linklist.cpp

#include "linklist.h"
#include<iostream>
using namespace std;
List::List()//初始化
{
    head=new Node;
    head->next=NULL;
    head->data=0;//头指针的数据域也不要浪费:用来存放链表长度

}
List::~List()//删除
{
    Node* del;
    while (head->next!=NULL)
    {
        del=head;
        head=head->next;
        delete del;
    }
    delete head;
}


void List::traverseList()//遍历
{
    Node *ph=head;
    cout<<"链表总长度为:"<<head->data<<endl;
    ph=ph->next;
    for(;ph!=NULL;ph=ph->next)
        cout<<ph->data<<"  ";
    cout<<endl;
}
void List::CreateListHead(int n)//头指针插入
//头插法:
//head->NULL;
//head->p1->NULL;
//head->p2->p1->NULL;
{
    for(int i=0;i<n;i++)
    {
        Node* cur=new Node;
        cur->data=i;
        cur->next=head->next;
        head->next=cur;
        head->data++;
    }
}

bool List::ListInsert(int i,ElemType d)
{
    Node *p=head,*cur;

    for(int j=1;j<i;j++)
    {
        p=p->next;
        if(p==NULL)
            return false;
    }
    cur=new Node;
    cur->data=d;
    cur->next=p->next;

    p->next=cur;

    head->data++;
    return true;
}

void List::CreateListEnd(int n)//末尾插入
//尾插法:
//head->NULL;
//head->p1->NULL;
//head->p1->p2->NULL;
{
    Node* cur,*end;
    end=head;
    for(int i=0;i<n;i++)
    {
        cur=new Node;
        cur->data=i;
        cur->next=end->next;
        end->next=cur;
        end=cur;
        head->data++;
    }
}
bool List::ListDelete(int i,ElemType& e)
{
    Node *p=head,*cur;

    for(int j=1;j<i;j++)
    {
        p=p->next;
        if(p==NULL)
            return false;
    }
    cur=p->next;//待删除节点
    e=cur->data;
    p->next=cur->next;//将待删除节点的后一个节点赋给其前一个节点
    head->data--;
    delete cur;
    return true;
}

bool List::GetElem(int i,ElemType& e)
{
    Node* p=head;

    for(int j=0;j<i;j++)
    {
        p=p->next;
        if(p==NULL)
            return false;
    }
    e=p->data;
    return true;
}

/*
 *这个程序是原始版本的程序,这个程序的思路更加清晰,下面一个程序是改进的程序,代码更加简洁。
 */
/*
void List::Reverse()//翻转链表
{
    Node* cur=head;//头插法
    Node* newhead,*tmp;

    //初始化新的头结点
    newhead=head;
    cur=cur->next;//旧链表的头结点被删除(赋给了新的头结点)
    newhead->next=NULL;//注意这一句和上一句不能颠倒,不然cur无法向后移

    while (cur)
    {
        tmp=cur;
        cur=cur->next;//顺序删旧链表的元素
        tmp->next=newhead->next;//被删掉的元素用头插法插入新的头结点
        newhead->next=tmp;
    }
    head= newhead;//这一步是多余的,因为新头和旧头都是指向同一位置,其实newhead是一个多余变量,直接用head也是可以完成任务的。
}
*/

void List::Reverse()//翻转链表
{
    Node* cur,* tmp;//头插法

    //初始化新的头结点
    cur=head;
    cur=cur->next;//旧链表的头结点被删除(赋给了新的头结点)
    head->next=NULL;//注意这一句和上一句不能颠倒,不然cur无法向后移

    while (cur)
    {
        tmp=cur;
        cur=cur->next;//顺序删旧链表的元素
        tmp->next=head->next;//被删掉的元素用头插法插入新的头结点
        head->next=tmp;
    }
}

(3)主程序main.cpp

#include <iostream>
#include"linklist.h"

using namespace std;

int main()
{

    List list;
    bool success;
    cout<<"                  初始化"<<endl;
    list.traverseList();

    List list1;
    list1.CreateListEnd(10);
    cout<<endl<<endl<<"         尾插法新建单链表 "<<endl;
    list1.traverseList();

    List list2;
    cout<<endl<<endl<<"         头插法新建单链表 "<<endl;
    list2.CreateListHead(10);
    list2.traverseList();

    cout<<endl<<endl<<"             元素插入"<<endl;
    list2.ListInsert(5,10);
    list2.traverseList();

    cout<<endl<<endl<<"             元素删除"<<endl;
    ElemType a;
    list2.ListDelete(5,a);
    cout<<"被删除的元素为:"<<a<<"  ";
    list2.traverseList();

    cout<<endl<<endl<<"             元素查找"<<endl;
    list2.traverseList();
    success=list2.GetElem(3,a);
    if(!success)
        cout<<"error"<<endl;
    else
        cout<<"被查找的元素为:"<<a<<endl;

    cout<<endl<<endl<<"             逆置链表"<<endl;
    cout<<"原链表"<<endl;
    list2.traverseList();
    list2.Reverse();
    cout<<endl<<"逆置链表"<<endl;
    list2.traverseList();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wanzhen4330/article/details/81605256