关于双链表的操作

作业1

在示例的基础上,实现如下功能:

  1. 链表添加节点功能
    1. bool addNode(list* plist,int nVal);
    2. 参数:plist,要追加节点的链表指针,nVal,节点值
    3. 返回值:是否成功
    4. 要求内部有合法性验证
    5. 节点添加于链表尾部
  2. 链表删除节点功能
    1. bool delNode(list* plist);
    2. 参数:plist,链表指针
    3. 返回值:是否成功
    4. 要求内部有合法性验证
    5. 删除尾部节点
  3. 链表遍历功能
    1. void traverse(list* plist,int nDir);
    2. 参数:plist,链表指针,nDir,遍历方向:0-正向,1-反向
    3. 要求内部有合法性验证
    4. 遍历时打印每个节点值
  4. 链表保存到文件
    1. void savelist(list* plist);
    2. 参数:plist,链表指针
    3. 要求内部有合法性验证
    4. 仅保存节点值,保存的数据文件是1列多行,数据文件名为data.txt
  5. 从数据文件读取数据并创建链表
    1. void readlist(list* plist);
    2. 参数:plist,链表指针
    3. 数据文件名称默认为data.txt,若文件中包含有效数据,则创建链表,依次读出每个节点的值,并添加到链表中;否则返回。
  6. (附加,可选做)节点删除功能(指定索引)
    1. bool delNode(list* plist,int nIdx);
    2. 参数:plist,链表指针,nIdx,要删除的节点索引
    3. 返回值:是否成功
    4. 要求内部有合法性验证
    5. 头节点索引认为是0,依次增加
  7. (附加,可选做)节点插入功能(指定索引)
    1. bool insertNode(list* plist,int nVal,int nIdx);
    2. 参数:plist,链表指针,nVal,节点值,nIdx,节点插入索引
    3. 返回值:是否成功
    4. 要求内部有合法性验证
    5. 头节点索引认为是0,依次增加。若指定位置不合法,则返回false
// 22309132作业1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;

typedef struct LNode {
    int data;
    struct LNode* next;     //定义一个LNode的指针
    struct LNode* prior;
}LNode;

LNode* InitList(LNode* L) {//初始化双链表
    L = (LNode*)malloc(sizeof(LNode));
    L->prior = NULL;
    L->next = NULL;
    return L;
}

bool addNode(LNode* plist, int nVal) {
    LNode* p = plist;
    while ((p->next)!=NULL)  //寻找尾结点
    {
        p = p->next;
    }
    LNode* L = (LNode*)malloc(sizeof(LNode));
    L->data = nVal;
    L->prior = p;
    p->next = L;
    p = L;  //p重新指向尾结点
    p->next = NULL;
    if (((p->data) == nVal) && ((p->next) == NULL)&&((p->prior)!=NULL))
        return true;
    else
    {
        return false;
    }
}

bool delNode(LNode* plist) {
    LNode* p = plist;
    while ((p->next->next) != NULL)  //寻找尾结点的前一个结点
    {
        p = p->next;
    }
    p->next = NULL;  //删除尾结点
    free(p->next);//释放内存
    if ((p != NULL) && ((p->next) == NULL)) {
        return true;
    }
    else
    {
        return false;
    }
}

void traverse(LNode* plist, int nDir) {
    LNode* pl = plist;
   // LNode* p = pl->next;
    if (nDir == 0) {
        while ((pl->next)!=NULL)
        {
            cout << pl->next->data << endl;
            pl = pl->next;
        }
    }
    else if(nDir == 1){
        while ((pl->next)!=NULL)  //寻找尾结点
        {
            pl = pl->next;
        }
        while ((pl->prior)!=NULL)
        {
            cout << pl->data << endl;
            pl = pl->prior;
        }
    }
}

void savelist(LNode* plist) {
    LNode* p = plist;
    ofstream fin;
    fin.open("data.txt");
    while ((p->next) != NULL) {
        if ((p->next->next)==NULL)
        {
            fin << p->next->data;
        }
        else
        {
            fin << p->next->data << endl;
        }
        p = p->next;
    }
}

void readlist(LNode* plist) {
    LNode* p = plist;
    ifstream infile("data.txt", ios::in);
    if (!infile) {
        cout << "文件打开失败!" << endl;
        return;
    }
    while (infile)
    {
        int data;
        if (!(infile >> data)) {
            break;  // break if read was unsuccessful
        }
        LNode* L = (LNode*)malloc(sizeof(LNode));
        L->data = data;
        p->next = L;
        L->prior = p;
        L->next = nullptr;
        p = L;
    }
}

bool delNode(LNode* plist, int index) {
    // 如果链表为空
    if (plist == NULL || index < 0) {
        cout << "链表为空" << endl;
        return false;
    }

    LNode* current = plist;
    int count = 0;//头结点索引是0(头结点不存储数据)

    // 找到要删除的节点
    while (current != NULL && count < index) {
        current = current->next;
        count++;
    }

    // 如果找不到要删除的节点
    if (current == NULL) {
        cout << "can not found node!" << endl;
        return false;
    }

    // 如果节点是头节点
    if (current->prior == NULL) {
        plist = current->next;
        if (current->next != NULL) {
            current->next->prior = NULL;
            
        }
    }
    // 如果节点是尾节点
    else if (current->next == NULL) {
        current->prior->next = NULL;
    }
    // 如果节点在链表中间
    else {
        current->prior->next = current->next;
        current->next->prior = current->prior;
    }
    free(current);
    return true;
}



bool insertNode(LNode* plist, int nVal, int nIdx) {
    LNode* newNode = (LNode*)malloc(sizeof(LNode));
    newNode->data = nVal;

    LNode* current = plist;
    int count = 0;

    // 找到指定索引位置的节点
    while (current != NULL && count < nIdx) {
        current = current->next;
        count++;
    }

    // 如果找到了指定的位置
    if (current != NULL) {
        newNode->next = current;
        newNode->prior = current->prior;
        current->prior->next = newNode;
        current->prior = newNode;
        return true; // 插入成功
    }
    else {
        cout << "插入失败" << endl;
        return false; // 插入失败
    }
}

int main()
{
    LNode* Plist=nullptr;
    Plist = InitList(Plist);
    //1.随机生成10个整型数,并逐一添加到链表中
    LNode* p = Plist;
    srand(time(0));
    for (int i = 0; i < 10; i++)
    {
        addNode(Plist, (int)rand());
    }
 //   traverse(Plist, 0);//测试
    //2. 删除结点
    delNode(Plist);
 //   traverse(Plist, 0);//测试
    //3. 删除节点(指定索引)
    delNode(Plist, 1);
 //   traverse(Plist, 0);//测试
    //4. 追加节点
    addNode(Plist, 66);
 //   traverse(Plist, 0);//测试
    //5. 追加节点(指定索引)
    insertNode(Plist, 666, 5);
    //6. 遍历当前链表
    traverse(Plist, 0);
    traverse(Plist, 1);
    //7. 保存链表到数据文件
    savelist(Plist);
    //8. 读取数据文件,并遍历
    LNode* Plist1 = nullptr;
    Plist1 = InitList(Plist1);
    readlist(Plist1);
    traverse(Plist1, 0);
    

}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值