数据结构与算法学习cpp(一):链表

1、哨兵节点

带头链表中,不存储任何数据的头节点就是一种哨兵节点,可以简化普通单链表插入、删除代码。

1.1 不带头链表操作:

1、插入:

if (head == null)//当前链表为空
{
	head = new_node;
}
else
{
	new_node->next = p->next;
	p->next = new_node;
}

2、删除:

if (head->next == null) //当前为最后一个元素
{
   head = null;
}
else
{
	p->next = p->next->next;
}

1.2 带头链表操作:

若当前链表为空,则head->nextNULL,插入操作为:

new_node->next = head->next;//NULL
head->next = new_node;

若当前仅剩最后一个元素,则该元素为head->next,此时head->next->nextNULL,删除操作为:

head->next = head->next->next;//NULL

可以看出,在任何时候,不管链表是不是空,head 指针都会一直指向这个哨兵结点,所以插入第一个结点和插入其他结点,删除最后一个结点和删除其他结点,都可以统一为相同的代码实现。

除了链表外,平时代码中也可以使用哨兵节点的方式来简化判断逻辑。

2、链表操作

一句废话:平时工作似乎curd或直接用容器就可,但是写这些东西可以提高代码能力。

2.1 链表类:

struct ListNode
{
    int data;             //数据
    ListNode* next; //指向下一节点指针
    ListNode()
    {
        data = NULL;
        next = nullptr;
    }
};
//链表类
class LinkList
{
public:
    LinkList();         //构造
    ~LinkList();        //析构
    void print();       //打印链表元素
    inline int getLength()
    {
        return length;
    };
    void pushHead(int data);    //头插
    void pushBack(int data);    //尾插
    void insert(int data, int position); //插入指定位置
    void remove(int position); //删除指定位置元素
    ListNode* findNode(int position);    //查找第position个元素
    void reverse();             //链表反转
private:
    ListNode* head;
    int length;
};

2.2 构造(新建)、析构(删除):

LinkList::LinkList()
{
    head = new ListNode();
    head->next = nullptr;
    head->data = NULL;
    length = 0;
}
LinkList::~LinkList()
{
    if (length == 0)
    {
        delete head;    //删除头节点空间
        head = nullptr;    
        return;
    }
    ListNode* p = head->next;
    delete head;
    while(p != nullptr)
    { 
        ListNode* tmpptr = p->next;
        delete p;
        p = tmpptr;
    }
    length = 0;
}

2.3 打印(遍历节点):

void LinkList::print()
{
    if (length == 0) return;
    ListNode* temp = head->next;
    cout <<"current list:"<< endl;
    int i;
    for (i = 0; i < length; i++)
    {
        cout << setw(4) <<temp->data;
        temp = temp->next;
    }
    cout << endl << endl;

    temp = nullptr;
}

2.4 定位节点:

ListNode* LinkList::findNode(int position)
{
    ListNode* temp = new ListNode();
    if (position > length+1)
    {
        cout<<"position"<<position<<"out of range!" << endl;
        temp->data = NULL;
        temp->next = nullptr;
        return temp;
    }
    temp = head;
    while (position--)
    {
        temp = temp->next;
    }
    return temp;
}

2.5 头插:

头插示例:
head->1->null;
插入2:head->2->1->null;
插入3:head->3->2->1->null;

void LinkList::pushHead(int data)    //头插
{
    ListNode* cur = new ListNode();
    cur->data = data;
    cur->next = head->next;
    head->next = cur;
    cur = nullptr;
    length++;
    return;
}

2.6 尾插:

尾插示例:
head->1->null;
插入2:head->1->2->null;
插入3:head->1->2->3->null;

void LinkList::pushBack(int data)    //尾插
{
    ListNode* cur = new ListNode();
    cur->data = data;
    cur->next = nullptr;
    ListNode* pre = findNode(length); //找到当前最后一节点
    pre->next = cur;
    length++;
    return;
}

2.7 指定位置插:

void LinkList::insert(int data, int position)//指定位置插
{
    if (position > length+1 || position < 1)
    {
        cout << "position" << position << "out of range" << endl;
        cout << endl;
        return;
    }
    if (position == length+1)
    {
        pushBack(data);
    }

    ListNode* pre = findNode(position-1);
    ListNode* cur = new ListNode();

    cur->data = data;
    cur->next = pre->next;
    
    pre->next = cur;
    length++;
    return;
}

2.7 删除指定节点:

找到待删除节点的前一个结点执行操作,别忘记释放空间。

void LinkList::remove(int position)
{
    if (position > length + 1 || position < 1)
    {
        cout << "position" << position << "out of range" << endl;
        cout << endl;
        return;
    }
    ListNode* pre = findNode(position - 1);//找到前节点
    ListNode* cur = pre->next;
    pre->next = cur->next;
    delete cur;
    length--;
}

2.8 反转链表:

反转示例:
head->1->2->3->4->5->null;
反转为:
head->5->4->3->2->1->null

void LinkList::reverse()
{
    if (length < 2)
    {
        return;
    }
    ListNode* pre = head->next;
    ListNode* cur = pre->next;
 
    while (cur)
    {
        ListNode* next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }

    head->next->next = nullptr;
    head->next = pre;
}

反转链表较基础操作稍微复杂些,在此作简要说明。
思路:
使用两个指针ListNode* preListNode* cur,要做的就是将原链表pre->cur方向,更改为cur->pre,从第一个节点开始,没变换一次方向就将两个指针向后移动一位,一直迭代到链表结束;
图示:
在这里插入图片描述

2.9 测试及结果:

int main()
{
    LinkList Testlist;
    int i = 1;
    for (i = 1; i < 6; i++)
    {
        Testlist.pushBack(i);
    }
    Testlist.print();

    Testlist.insert(6,3);
    Testlist.print();

    Testlist.reverse();
    Testlist.print();
    
    return 0;
}

结果:在这里插入图片描述
gitee:cpp代码(vs2019可运行)

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值