【算法笔记】设计链表

设计链表问题

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

解决问题

链表的定义

class ListNode {
   int val;
   ListNode next;
   
  //传入结点值的构造方法
   ListNode(int val) {
       this.val = val;
       next=null;
   }
}

类中的属性和构造函数
这里采用的虚拟头结点,为了方便后面的插入等操作,比如addAtIndex(index,val)方法中,就不需要将头结点拿出来单独处理,可以统一处理所有结点。注意:真正的头结点为虚拟头结点的下一个结点。

class MyLinkedList {

    //链表大小
    int size;
    //链表的虚拟头结点
    ListNode dummyHead;

    public MyLinkedList() {
        size=0;
        dummyHead=new ListNode(0);
    }

get(index)
取链表中第index个节点的值。如果索引无效,则返回-1。

  • 索引无效
    index超出链表的大小或者小于0,链表索引从0开始,所以为index>=size或者index<时返回-1
  • 索引有效,取index结点值
    通过循环移动指针到index位置的结点上,再取出值
 //取链表中第index个节点的值。如果索引无效,则返回-1。
 public int get(int index) {
     //索引大于等于链表大小,或者小于零,无效返回-1
     if(index>=size||index<0){
         return -1;
     }
     //定一个指针执行头结点
     ListNode cur=dummyHead.next;
     //指针移动到index位置的结点上
     while(index-->0){
         cur=cur.next;
     }
     return cur.val;
 }

addAtHead(val)
在链表的第一个元素之前添加一个值为val的节点。插入后,新节点将成为链表的第一个节点。

  • 创建值为val的新结点
  • 将新结点的指针指向虚拟头结点的下一个结点,即头结点
  • 讲虚拟头结点的指针指向新结点
  • 链表长度加1
 //在链表的第一个元素之前添加一个值为val的节点。插入后,新节点将成为链表的第一个节点。
 public void addAtHead(int val) {
 	//创建值为val的新结点
     ListNode newNode=new ListNode(val);
     //将新结点的指针指向虚拟头结点的下一个结点,即头结点
     newNode.next=dummyHead.next;
     //讲虚拟头结点的指针指向新结点
     dummyHead.next=newNode;
     //链表长度加1
     size++;
 }

addAtTail(val)
将值为val 的节点追加到链表的最后一个元素。

  • 创建值为val的新结点
  • 创建指针指向虚拟头结点
  • 通过循环,将指针移动到尾结点
  • 将新结点追加到尾结点后面
  • 链表长度加1
//将值为val 的节点追加到链表的最后一个元素。
public void addAtTail(int val) {
	//创建值为val的新结点
    ListNode newNode=new ListNode(val);
    //创建指针指向虚拟头结点
    ListNode cur=dummyHead;
    //通过循环,将指针移动到尾结点
    while(cur.next!=null){
        cur=cur.next;
    }
    //将新结点追加到尾结点后面
    cur.next=newNode;
    //链表长度加1
    size++;
}

addAtIndex(index,val)
在链表中的第index个节点之前添加值为val 的节点。如果index等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。

(1)先判断index是否大于size,大于直接退出。
(2)插入处理,因为使用了虚拟头结点,所以不需要单独处理头结点。

  • 创建值为val的新结点,创建指针指向虚心头结点
  • 因为要移动在第index结点之前添加结点,所以需要找到第index结点前一个结点的索引,将指针移动到这个索引位置
  • 进行插入,链表大小加1
 //在链表中的第index个节点之前添加值为val 的节点。如果index等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
 public void addAtIndex(int index, int val) {
 	//先判断index是否大于size,大于直接退出。
     if(index>size){
         return;
     }
     //创建值为val的新结点
     ListNode newNode=new ListNode(val);
     //创建指针指向头结点
     ListNode cur=dummyHead;
     //移动指针到index的前一个,因为我们是从虚拟头结点开始的,所以移动index步即是index所以位置的前一个结点
     while(index-->0){
         cur=cur.next;
     }
     //插入结点
     newNode.next=cur.next;
     cur.next=newNode;
     size++;
 }

deleteAtIndex(index)
如果索引index 有效,则删除链表中的第index 个节点。

  • 有效的条件为索引大于等于0,小于链表的总大小,index>=0&&index<size
  • 创建一个指针指向虚拟头结点
  • 在单链表中,删除某个结点需要知道该节点的前一个结点的索引,所以移动指针指向索引index前面的结点索引
  • 删除操作,将删除位置前面结点的指针指向删除位置后面的结点,链表大小-1
 //如果索引index 有效,则删除链表中的第index 个节点。
 public void deleteAtIndex(int index) {
     ListNode cur=dummyHead;
     if(index>=0&&index<size){
     	//移动指针指向索引index前面的结点索引
         while (index-->0){
             cur=cur.next;
         }
         //删除操作,将删除位置前面结点的指针指向删除位置后面的结点
         cur.next=cur.next.next;
		//链表大小-1
         size--;
     }
 }

整体代码

class MyLinkedList {

    //链表大小
    int size;
    //链表的虚拟头结点
    ListNode dummyHead;


    public MyLinkedList() {
        size=0;
        dummyHead=new ListNode(0);
    }

    //取链表中第index个节点的值。如果索引无效,则返回-1。
    public int get(int index) {
        //索引大于等于链表大小,或者小于零,无效返回-1
        if(index>=size||index<0){
            return -1;
        }
        //定一个指针执行头结点
        ListNode cur=dummyHead.next;
        //指针移动到index位置的结点上
        while(index-->0){
            cur=cur.next;
        }
        return cur.val;
    }

    //在链表的第一个元素之前添加一个值为val的节点。插入后,新节点将成为链表的第一个节点。
    public void addAtHead(int val) {
        //创建值为val的新结点
        ListNode newNode=new ListNode(val);
        //将新结点的指针指向虚拟头结点的下一个结点,即头结点
        newNode.next=dummyHead.next;
        //讲虚拟头结点的指针指向新结点
        dummyHead.next=newNode;
        //链表长度加1
        size++;
    }

    //将值为val 的节点追加到链表的最后一个元素。
    public void addAtTail(int val) {
        //创建值为val的新结点
        ListNode newNode=new ListNode(val);
        //创建指针指向虚拟头结点
        ListNode cur=dummyHead;
        //通过循环,将指针移动到尾结点
        while(cur.next!=null){
            cur=cur.next;
        }
        //将新结点追加到尾结点后面
        cur.next=newNode;
        //链表长度加1
        size++;
    }

    //在链表中的第index个节点之前添加值为val 的节点。如果index等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
    public void addAtIndex(int index, int val) {
        //先判断index是否大于size,大于直接退出。
        if(index>size){
            return;
        }
        //创建值为val的新结点
        ListNode newNode=new ListNode(val);
        //创建指针指向头结点
        ListNode cur=dummyHead;
        //移动指针到index的前一个,因为我们是从虚拟头结点开始的,所以移动index步即是index所以位置的前一个结点
        while(index-->0){
            cur=cur.next;
        }
        //插入结点
        newNode.next=cur.next;
        cur.next=newNode;
        size++;
    }

    //如果索引index 有效,则删除链表中的第index 个节点。
    public void deleteAtIndex(int index) {
        ListNode cur=dummyHead;
        //移动指针指向索引index前面的结点索引
        if(index>=0&&index<size){
            while (index-->0){
                cur=cur.next;
            }
            //删除操作,将删除位置前面结点的指针指向删除位置后面的结点
            cur.next=cur.next.next;
            //链表大小-1
            size--;
        }
    }
}
面向对象程序设计课程作业 1. 请创建一个数据类型为T的链表类模板List,实现以下成员函数: 1) 默认构造函数List(),将该链表初始化为一个空链表(10分) 2) 拷贝构造函数List(const List& list),根据一个给定的链表构造当前链表(10分) 3) 析构函数~List(),释放链表中的所有节点(10分) 4) Push_back(T e)函数,往链表最末尾插入一个元素为e的节点(10分) 5) operator<<()友元函数,将链表的所有元素按顺序输出(10分) 6) operator=()函数,实现两个链表的赋值操作(10分) 7) operator+()函数,实现两个链表的连接,A=B+C(10分) 2. 请编写main函数,测试该类模板的正确性: 1) 用List模板定义一个List类型的模板类对象int_listB,从键盘读入m个整数,调用Push_back函数将这m个整数依次插入到该链表中;(4分) 2) 用List模板定义一个List类型的模板类对象int_listC,从键盘读入n个整数,调用Push_back函数将这n个整数依次插入到该链表中;(4分) 3) 用List模板定义一个List类型的模板类对象int_listA,调用List的成员函数实现A = B + C;(4分) 4) 用cout直接输出int_listA的所有元素(3分) 5) 用List模板定义List类型的模板类对象double_listA, double_listB, double_listC,重复上述操作。(15分) 3. 输入输出样例: 1) 输入样例 4 12 23 34 45 3 56 67 78 3 1.2 2.3 3.4 4 4.5 5.6 6.7 7.8 2) 输出样例 12 23 34 45 56 67 78 1.2 2.3 3.4 4.5 5.6 6.7 7.8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值