【数据结构】链表的十三种操作

菜单

cpp 复制代码
//0、显示菜单
void menu()
{
    cout << "菜单:" << endl;
    cout << "1.初始化或重置链表" << endl;
    cout << "2.销毁链表" << endl;
    cout << "3.清空链表" << endl;
    cout << "4.链表长度" << endl;
    cout << "5.指定位置的元素值" << endl;
    cout << "6.链表已存在元素的位序" << endl;
    cout << "7.求输入元素的直接前驱" << endl;
    cout << "8.求输入元素的直接后继" << endl;
    cout << "9.在第i个位置插入一个元素" << endl;
    cout << "10.删除第i个元素" << endl;
    cout << "11.输出有的链表元素" << endl;
    cout << "12.初始化并用头插法(或尾插法)输入元素" << endl;
    cout << "13.实现单链表的逆序存放" << endl;
    cout << "-1.退出程序" << endl;
}

定义结构体

cpp 复制代码
// 定义结构体
typedef struct DNode
{
    EleType data;
    struct DNode *prior,*next;
}Dnode,*DLinkList;

1.初始化或重置链表

cpp 复制代码
// 1、初始化双向链表
bool Init_linkList(DLinkList& L)
{
    L = (DNode*) malloc(sizeof(DNode));
    if(L == nullptr)
        return false;
    else
    {
        L->prior = nullptr;
        L->next = nullptr;
        return true;
    }
}

2.销毁链表

注:销毁链表时需要循环释放每个结点所占用的空间。

cpp 复制代码
// 2、销毁链表
void DestroyLink(DNode *L){//为了避免内存泄露,每次创建链表运行完程序应将创建的链表销毁,避免内存泄露
    DNode *temp;
    DNode *pre;
    temp= L->next;
    while(temp != nullptr){
        pre = temp;
        temp = temp->next;
        free(pre);
    }
    free(L);
}

3.清空链表

cpp 复制代码
// 3、清空双链表
bool ClearDLink(DNode* L)
{
    DNode *temp;
    DNode *pre;
    temp= L->next;
    while(temp != nullptr){
        pre = temp;
        temp = temp->next;
        free(pre);
    }
    L->next = nullptr;
    L->prior = nullptr;
    if(L->next == nullptr)
        return true;
    else
        return false;
}

4.链表长度

cpp 复制代码
// 4、求双链表长度
int LengthLink(Dnode*L)
{
    int cnt = 0;
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        temp = temp->next;
        cnt ++;
    }
    return cnt;
}

5.指定位置的元素值

cpp 复制代码
// 5、指定位置元素
int elem_check(Dnode*L,int address)// 判断这个位置是否合法
{
    int cnt = LengthLink(L);
    if(address <= 0 || address > cnt) return false;
    return true;
}

EleType ElemLink(Dnode *L,int address)// 如果这个位置合法,则进行查找
{
    int cnt = 0;
    EleType flag;
    DNode *temp;
    DNode *pre;
    temp= L->next;
    while(temp != nullptr){
        pre = temp;
        temp = temp->next;
        if(++ cnt == address) flag = pre->data;
    }
    return flag;
}

6.链表已存在元素的位序

cpp 复制代码
// 6.链表已存在元素的位序

bool judge_address(Dnode *L,EleType elem)
{
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        if(temp->data == elem) return true;
        temp = temp->next;
    }
    return false;
}

int AddressLink(Dnode *L,EleType elem)
{
    int address = 0;
    int cnt = 0;
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        cnt ++;
        if(temp->data == elem) address = cnt;
        temp = temp->next;
    }
    return address;
}

7.求输入元素的直接前驱

cpp 复制代码
// 7.求输入元素的直接前驱

bool judge_before(Dnode *L,EleType elem)
{
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        if(temp->data == elem)
        {
            if(temp->prior == L) return false;
            else return true;
        }
        temp = temp->next;
    }
    return false;
}

EleType BeforeLink(Dnode *L,EleType elem)
{
    EleType flag;
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        if(temp->data == elem)
        {
            flag = temp->prior->data;
        }
        temp = temp->next;
    }
    return flag;
}

求前驱是指,输入一个元素值(而不是位置),求该元素在顺序表中的直接前驱元素值。

8.求输入元素的直接后继

cpp 复制代码
// 8.求输入元素的直接后继
bool judge_after(Dnode *L,EleType elem)
{
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        if(temp->data == elem)
        {
            if(temp->next == nullptr) return false;
            else return true;
        }
        temp = temp->next;
    }
    return false;
}

EleType AfterLink(Dnode *L,EleType elem)
{
    EleType flag;
    DNode *temp;
    temp= L->next;
    while(true){
        if(temp->data == elem)
        {
            flag = temp->next->data;
            break;
        }
        temp = temp->next;
    }
    return flag;
}

求后继是指:输入一个元素值(而不是位置),求该元素在顺序表中的直接后继元素值。

9.在第i个位置插入一个元素

cpp 复制代码
// 9.在第i个位置插入一个元素

void LinkListInit(Dnode* L,int address,EleType elem)
{
    Dnode* l;
    l = (DNode*) malloc(sizeof(DNode));
    l->data = elem;
    int cnt = 0;
    DNode *temp;
    temp= L->next;
    int len = LengthLink(L);
    if(address == len + 1)
    {
        temp = L;
        while(true)
        {
            if(temp->next == nullptr)
            {
                l->next = nullptr;
                l->prior = temp;
                temp->next = l;
                return;
            }
            temp = temp->next;
        }
    }
    else
    {
        while(temp != nullptr){
            cnt ++;
            if(cnt == address)
            {
                l->next = temp;
                l->prior = temp->prior;
                temp->prior->next = l;
                temp->prior = l;
                return;
            }
            temp = temp->next;
        }
    }
}

10.删除第i个元素

cpp 复制代码
// 10.删除第i个元素
void drop(Dnode* L,int address)
{
    int cnt = 0;
    DNode *temp;
    temp= L->next;
    int len = LengthLink(L);
    if(len == address)
    {
        while(true)
        {
            if(temp->next == nullptr)
            {
                temp->prior->next = nullptr;
                free(temp);
                return;
            }
            temp = temp->next;
        }
    }
    while(temp != nullptr){
        cnt ++;
        if(cnt == address)
        {
            temp->prior->next = temp->next;
            temp->next->prior = temp->prior;
            free(temp);
            return;
        }
        temp = temp->next;
    }
}

11.输出有的链表元素

cpp 复制代码
// 11.输出有的链表元素
void show(Dnode* L)
{
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        cout << temp->data << "  ";
        temp = temp->next;
    }
    cout << endl;
}

12.清空链表并用头插法(或尾插法)输入元素

cpp 复制代码
// 12.清空并用头插法(或尾插法)输入元素
void show12(Dnode* L,int sum)
{
    ClearDLink(L);
    for(int i = 0; i < sum; i ++)
    {
        Dnode* l;
        l = (DNode*) malloc(sizeof(DNode));
        EleType num;
        cin >> num;
        l->data = num;
        l->next = L->next;
        l->prior = L;
        if(L->next != nullptr)
        {
            L->next->prior = l;
        }
        L->next = l;
    }
    show(L);
}

13.实现单链表的逆序存放

cpp 复制代码
void show13(Dnode* L)
{
    queue<EleType> q;
    DNode *temp;
    DNode *p;
    temp= L->next;
    while(temp != nullptr){
        q.push(temp->data);
        p = temp;
        temp = temp->next;
        free(p);
    }
    L->next = nullptr;
    L->prior = nullptr;
    while(!q.empty())
    {
        EleType s;
        s = q.front();
        q.pop();
        DNode* l;
        l = (Dnode*) malloc(sizeof(DNode));
        l->data = s;
        l->next = L->next;
        l->prior = L;
        if(L->next != nullptr)
        {
            L->next->prior = l;
        }
        L->next = l;
    }
}

要求:所有的提示语和输出语句不允许出现在自定义的函数中(输出函数除外),只能在main函数中出现提示语。

注意,每个功能模块一定要考虑非法的情况,并作出相应的提示,例如:求前驱,要分别能够测试第一个元素的前驱、其他正常的元素的前驱、输入一个在表中不存在的元素求其前驱,这三种情况应给出相应的提示语和结果值;插入和删除时要考虑插入或删除的位置是否合法等。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef int EleType;

// 定义结构体
typedef struct DNode
{
    EleType data;
    struct DNode *prior,*next;
}Dnode,*DLinkList;

//0、显示菜单
void menu()
{
    cout << "菜单:" << endl;
    cout << "1.初始化或重置链表" << endl;
    cout << "2.销毁链表" << endl;
    cout << "3.清空链表" << endl;
    cout << "4.链表长度" << endl;
    cout << "5.指定位置的元素值" << endl;
    cout << "6.链表已存在元素的位序" << endl;
    cout << "7.求输入元素的直接前驱" << endl;
    cout << "8.求输入元素的直接后继" << endl;
    cout << "9.在第i个位置插入一个元素" << endl;
    cout << "10.删除第i个元素" << endl;
    cout << "11.输出有的链表元素" << endl;
    cout << "12.初始化并用头插法(或尾插法)输入元素" << endl;
    cout << "13.实现单链表的逆序存放" << endl;
    cout << "-1.退出程序" << endl;
}

// 1、初始化双向链表
bool Init_linkList(DLinkList& L)
{
    L = (DNode*) malloc(sizeof(DNode));
    if(L == nullptr)
        return false;
    else
    {
        L->prior = nullptr;
        L->next = nullptr;
        return true;
    }
}

// 2、销毁链表
void DestroyLink(DNode *L){//为了避免内存泄露,每次创建链表运行完程序应将创建的链表销毁,避免内存泄露
    DNode *temp;
    DNode *pre;
    temp= L->next;
    while(temp != nullptr){
        pre = temp;
        temp = temp->next;
        free(pre);
    }
    free(L);
}


// 3、清空双链表
bool ClearDLink(DNode* L)
{
    DNode *temp;
    DNode *pre;
    temp= L->next;
    while(temp != nullptr){
        pre = temp;
        temp = temp->next;
        free(pre);
    }
    L->next = nullptr;
    L->prior = nullptr;
    if(L->next == nullptr)
        return true;
    else
        return false;
}

// 4、求双链表长度
int LengthLink(Dnode*L)
{
    int cnt = 0;
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        temp = temp->next;
        cnt ++;
    }
    return cnt;
}

// 5、指定位置元素
int elem_check(Dnode*L,int address)
{
    int cnt = LengthLink(L);
    if(address <= 0 || address > cnt) return false;
    return true;
}
EleType ElemLink(Dnode *L,int address)
{
    int cnt = 0;
    EleType flag;
    DNode *temp;
    DNode *pre;
    temp= L->next;
    while(temp != nullptr){
        pre = temp;
        temp = temp->next;
        if(++ cnt == address) flag = pre->data;
    }
    return flag;
}

// 6.链表已存在元素的位序

bool judge_address(Dnode *L,EleType elem)
{
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        if(temp->data == elem) return true;
        temp = temp->next;
    }
    return false;
}

int AddressLink(Dnode *L,EleType elem)
{
    int address = 0;
    int cnt = 0;
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        cnt ++;
        if(temp->data == elem) address = cnt;
        temp = temp->next;
    }
    return address;
}

// 7.求输入元素的直接前驱

bool judge_before(Dnode *L,EleType elem)
{
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        if(temp->data == elem)
        {
            if(temp->prior == L) return false;
            else return true;
        }
        temp = temp->next;
    }
    return false;
}

EleType BeforeLink(Dnode *L,EleType elem)
{
    EleType flag;
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        if(temp->data == elem)
        {
            flag = temp->prior->data;
        }
        temp = temp->next;
    }
    return flag;
}

// 8.求输入元素的直接后继
bool judge_after(Dnode *L,EleType elem)
{
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        if(temp->data == elem)
        {
            if(temp->next == nullptr) return false;
            else return true;
        }
        temp = temp->next;
    }
    return false;
}

EleType AfterLink(Dnode *L,EleType elem)
{
    EleType flag;
    DNode *temp;
    temp= L->next;
    while(true){
        if(temp->data == elem)
        {
            flag = temp->next->data;
            break;
        }
        temp = temp->next;
    }
    return flag;
}


// 9.在第i个位置插入一个元素

void LinkListInit(Dnode* L,int address,EleType elem)
{
    Dnode* l;
    l = (DNode*) malloc(sizeof(DNode));
    l->data = elem;
    int cnt = 0;
    DNode *temp;
    temp= L->next;
    int len = LengthLink(L);
    if(address == len + 1)
    {
        temp = L;
        while(true)
        {
            if(temp->next == nullptr)
            {
                l->next = nullptr;
                l->prior = temp;
                temp->next = l;
                return;
            }
            temp = temp->next;
        }
    }
    else
    {
        while(temp != nullptr){
            cnt ++;
            if(cnt == address)
            {
                l->next = temp;
                l->prior = temp->prior;
                temp->prior->next = l;
                temp->prior = l;
                return;
            }
            temp = temp->next;
        }
    }
}

// 10.删除第i个元素
void drop(Dnode* L,int address)
{
    int cnt = 0;
    DNode *temp;
    temp= L->next;
    int len = LengthLink(L);
    if(len == address)
    {
        while(true)
        {
            if(temp->next == nullptr)
            {
                temp->prior->next = nullptr;
                free(temp);
                return;
            }
            temp = temp->next;
        }
    }
    while(temp != nullptr){
        cnt ++;
        if(cnt == address)
        {
            temp->prior->next = temp->next;
            temp->next->prior = temp->prior;
            free(temp);
            return;
        }
        temp = temp->next;
    }
}

// 11.输出有的链表元素
void show(Dnode* L)
{
    DNode *temp;
    temp= L->next;
    while(temp != nullptr){
        cout << temp->data << "  ";
        temp = temp->next;
    }
    cout << endl;
}

// 12.初始化并用头插法(或尾插法)输入元素
void show12(Dnode* L,int sum)
{
    ClearDLink(L);
    for(int i = 0; i < sum; i ++)
    {
        Dnode* l;
        l = (DNode*) malloc(sizeof(DNode));
        EleType num;
        cin >> num;
        l->data = num;
        l->next = L->next;
        l->prior = L;
        if(L->next != nullptr)
        {
            L->next->prior = l;
        }
        L->next = l;
    }
    show(L);
}

void show13(Dnode* L)
{
    queue<EleType> q;
    DNode *temp;
    DNode *p;
    temp= L->next;
    while(temp != nullptr){
        q.push(temp->data);
        p = temp;
        temp = temp->next;
        free(p);
    }
    L->next = nullptr;
    L->prior = nullptr;
    while(!q.empty())
    {
        EleType s;
        s = q.front();
        q.pop();
        DNode* l;
        l = (Dnode*) malloc(sizeof(DNode));
        l->data = s;
        l->next = L->next;
        l->prior = L;
        if(L->next != nullptr)
        {
            L->next->prior = l;
        }
        L->next = l;
    }
}


int main()
{
    DLinkList L;
    int op = -1;
    bool flag = false;
    menu();
    while(op != 0)
    {
        cout << "<------------------------------>" << endl << "请输入你的选择:";
        cin >> op;
        if(op == 1)
        {
            // 1.初始化或重置链表
            if(Init_linkList(L))
            {
                cout << "初始化成功!" << endl;
                flag = true;
            }
            else cout << "初始化失败!" << endl;
        }else if(op == 2)
        {
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            // 2.销毁链表
            DestroyLink(L);
            flag = false;
            cout << "成功销毁链表!" << endl;
        }else if(op == 3)
        {
            // 3.清空链表
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            if(ClearDLink(L))
                cout << "清空链表成功!" << endl;
            else
                cout << "清空链表失败!" << endl;
        }else if(op == 4)
        {
            // 4.链表长度
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            int l = LengthLink(L);
            cout << "链表长度为:" << l << endl;
        }else if(op == 5)
        {
            // 5.指定位置的元素值
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            int address;
            cout << "请输入位置:";
            cin >> address;
            if(elem_check(L,address))
            {
                EleType ans = ElemLink(L,address);
                cout << "第" << address << "位置的元素为:" << ans << endl;
            }
            else
            {
                cout << "这个位置没有元素!" << endl;
            }
        }else if(op == 6)
        {
            // 6.链表已存在元素的位序
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            EleType elem;
            cout << "请输入查找的元素:";
            cin >> elem;
            if(judge_address(L,elem))
            {
                int address = AddressLink(L,elem);
                cout << "值" << elem << "的位置在" << address << endl;
            }
            else
            {
                cout << "链表中不存在这个值!" << endl;
            }
        }else if(op == 7)
        {
            // 7.求输入元素的直接前驱
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            EleType elem;
            cout << "请输入查找的元素:";
            cin >> elem;
            if(judge_before(L,elem))
            {
                EleType ans;
                ans = BeforeLink(L,elem);
                cout << "元素" << elem << "的直接前驱为:" << ans << endl;
            }
            else
            {
                cout << "这个值没有直接前驱!" << endl;
            }
        }else if(op == 8)
        {
            // 8.求输入元素的直接后继
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            EleType elem;
            cout << "请输入查找的元素:";
            cin >> elem;
            if(judge_after(L,elem))
            {
                EleType ans;
                ans = AfterLink(L,elem);
                cout << "元素" << elem << "的直接后继为:" << ans << endl;
            }
            else
            {
                cout << "这个值没有直接后继!" << endl;
            }
        }
        else if(op == 9)
        {
            // 9.在第i个位置插入一个元素
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            int len;
            len = LengthLink(L);
            int address;
            cout << "输入插入位置:";
            cin >> address;
            EleType elem;
            cout << "输入插入元素:";
            cin >> elem;
            if(address < 1 || address > len + 1)
            {
                cout << "这个位置不能插入元素" << endl;
            }
            else
            {
                LinkListInit(L,address,elem);
                cout << "插入成功!" << endl;
            }
        }
        else if(op == 10)
        {
            // 10.删除第i个元素
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            int address;
            cout << "请输入元素位置:";
            cin >> address;
            int len = LengthLink(L);
            if(address < 1 || address > len)
            {
                cout << "这个位置不能删除"<< endl;
                continue;
            }
            drop(L,address);
            cout << "删除成功!" << endl;
        }
        else if(op == 11)
        {
            // 11.输出有的链表元素
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            show(L);
        }
        else if(op == 12)
        {
            // 12.初始化并用头插法(或尾插法)输入元素
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            cout << "初始化并用头插法(或尾插法)输入元素" << endl;
            cout << "请输入插入元素个数:";
            int sum;
            cin >> sum;
            show12(L,sum);
        }
        else if(op == 13)
        {
            // 13.实现单链表的逆序存放
            if(!flag)
            {
                cout << "链表已被销毁" << endl;
                continue;
            }
            show13(L);
        }
        else if(op == -1) break;
    }
    cout << "程序结束!" << endl;
}
相关推荐
ULTRA??18 分钟前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++
凌云行者1 小时前
OpenGL入门005——使用Shader类管理着色器
c++·cmake·opengl
凌云行者1 小时前
OpenGL入门006——着色器在纹理混合中的应用
c++·cmake·opengl
~yY…s<#>1 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
可均可可2 小时前
C++之OpenCV入门到提高004:Mat 对象的使用
c++·opencv·mat·imread·imwrite
白子寰2 小时前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
小芒果_013 小时前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
XuanRanDev3 小时前
【每日一题】LeetCode - 三数之和
数据结构·算法·leetcode·1024程序员节
gkdpjj3 小时前
C++优选算法十 哈希表
c++·算法·散列表
代码猪猪傻瓜coding3 小时前
力扣1 两数之和
数据结构·算法·leetcode