单链表的基本操作及练习

目录

1.设计链表

2.链表的逆置

3.回文链表

4.两数相加


1.设计链表

     使用单链表实现这些功能:

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

typedef struct MyLinkedList{
    int val;
    struct MyLinkedList *next;
} MyLinkedList;

/** Initialize your data structure here. */

MyLinkedList* myLinkedListCreate() {                                    //初始化单链表(带头结点)
    MyLinkedList * obj = (MyLinkedList *)malloc(sizeof(MyLinkedList));    //分配空间
    obj->val = 0;
    obj->next = NULL;
    return obj;
}

/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
int myLinkedListGet(MyLinkedList* obj, int index) {
    if(index<0)                                 //索引无效
        return -1;
    MyLinkedList *p = obj;                      //指针p指向头结点
    for(int i=0; i<=index; i++){                //遍历链表,使指针p指向目标结点
        if(p->next == NULL)                     //索引无效
            return -1;
        else
            p = p->next;
    }
    return p->val;                              //返回目标结点的值
}

/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    MyLinkedList *s = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //分配空间
    s->val = val;
    s->next = NULL;
    MyLinkedList *p = obj;                      //指针p指向头结点
    if(p->next == NULL){                        //链表为空
        p->next = s;
        return;
    }else{
        s->next = p->next;                      //将s插入头结点之后
        p->next = s;
    }
}

/** Append a node of value val to the last element of the linked list. */
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    MyLinkedList *s = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //分配空间
    s->val = val;
    s->next = NULL;
    MyLinkedList *p = obj;
    while(p->next != NULL)                      //遍历链表寻找尾结点,使p指向尾节点
        p = p->next;
    p->next = s;                                //将s追加至p之后
}

/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    if(index<0)                                 //索引小于零,在头部插入结点
        myLinkedListAddAtHead(obj, val);
    MyLinkedList *p = obj;
    for(int i=0; i<index; i++){                 //遍历链表,使p指向目标结点的前驱结点
        if(p->next == NULL)                     //索引大于链表长度
            return;
        else
            p = p->next;
    }
    MyLinkedList *s = (MyLinkedList *)malloc(sizeof(MyLinkedList)); //分配空间
    s->val = val;
    if(p->next != NULL){                        //判断p是否是尾结点
        s->next = p->next;
    }else{                                      
        s->next = NULL;
    }
    p->next = s;                                //将s插入p结点之后,即目标结点之前
}
/** Delete the index-th node in the linked list, if the index is valid. */
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    if(index<0)                                 //索引无效
        return;
    MyLinkedList *p = obj;
    for(int i=0; i<index; i++){                 //遍历链表,使指针p指向目标结点的前驱结点
        if(p->next == NULL)                     //索引无效
            return;
        else
            p = p->next;
    }
    if(p->next == NULL)
        return;
    else
        p->next = p->next->next;
}

void myLinkedListFree(MyLinkedList* obj) {       //释放空间
    MyLinkedList *p = obj;                       //p指向要释放的结点
    MyLinkedList *s;                             //s指向要释放结点的后继结点
    while(p){                                    //循环遍历链表
        s = p->next;
        free(p);
        p = s;
    }
}

/**
 * Your MyLinkedList struct will be instantiated and called as such:
 * MyLinkedList* obj = myLinkedListCreate();
 * int param_1 = myLinkedListGet(obj, index);
 
 * myLinkedListAddAtHead(obj, val);
 
 * myLinkedListAddAtTail(obj, val);
 
 * myLinkedListAddAtIndex(obj, index, val);
 
 * myLinkedListDeleteAtIndex(obj, index);
 
 * myLinkedListFree(obj);
*/

2.链表的逆置

         采用头插法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* reverseList(struct ListNode* head)  //head第一带数据的结点   不带头指针
{
    struct ListNode *p,*pt;
	if(head==NULL||head->next==NULL) return head;
    p=head->next;        
	head->next=NULL;     
	while(p){
		pt=p;          
        p=p->next;       
		pt->next=head;
        head=pt;
	}
	return head;
}

struct ListNode* reverseList(struct ListNode* head)//head指向第一个带数据结点(首元结点) 
{
    
    struct ListNode *p,*q;
    p=head->next;
    head->next=NULL;
    while(p)
      {
          q=p;
          p=p->next;
          q->next=head->next;
          head->next=q;
      }
    return head;  
}

 带头结点的链表逆置(头插法)#无声胜有声

带头结点的链表逆置方法二 直接逆置

          单链表直接逆置(遍历,使各个结点的next指向其前驱结点,head指向最后一个结点)

//带头指针
struct ListNode* reverseList(struct ListNode* L)
{
    struct ListNode *pre,*p,*r;//r定位,为了找的p结点next断开后,后面的结点
    p=L->next;
    r=p->next;
    p->next=NULL;
     while(r)
      {
          pre=p;
          p=r;
          r=r->next;
          p->next=pre;
      }
    L->next=p;
    return L;

}

3.回文链表

    给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

    遍历链表,将其数据放在数组中,再利用双指针由两端往中间移动,判断是否相等

bool isPalindrome(struct ListNode* head){
    int data[100000];                       //创建数组  
    struct ListNode* q = head;
    int num=0;
    
    while(q != NULL){                       //遍历链表并将链表元素复制到数组中
        data[num] = q->val;
        q = q->next;
        ++num;
    }
    for(int i=0, j=num-1; i < j; ++i, --j){ //检查是否为回文链表
        if(data[i] != data[j])
            return false;
    }

    return true;
}


4.两数相加

       给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。(你可以假设除了数字 0 之外,这两个数都不会以 0 开头。)

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
	int i=0;
    struct ListNode* p1=l1;
    struct ListNode* p2=l2;       //创建两个指针分别指向l1,l2,防止修改原链表

    struct ListNode*p=(struct ListNode*)malloc(sizeof(struct ListNode));
    p->val=-1;
    p->next=NULL;                    //创建指针存放输出链表,p为头节点

    struct ListNode* f=p;          //结点f用来指向输出位置

    while(p1!=NULL || p2!=NULL){
        struct ListNode*d=(struct ListNode*)malloc(sizeof(struct ListNode));
        d->val=-1;
        d->next=NULL;
        f->next=d;
        f=f->next;         //创建结点并让f指向它

        //求和 注意:链表长度较短的一方会提前结束,因此需要判断一下是否已经指向最后一个结点,若指向最后一个结点,则需将其值用0表示;
        int sum=0;
        if(p1==NULL){
            sum=0+p2->val+i;
            p2=p2->next;
        }
        else if(p2==NULL){
            sum=0+p1->val+i;
            p1=p1->next;
        }
        else{
            sum=p1->val+p2->val+i;
            p1=p1->next;
            p2=p2->next;
        } 

        //判断和是否大于10,若大于则将进位设置为1,否则为0;将余数存在结点中
        if(sum>=10){
            i=1;
            f->val=sum%10;
        }
        else{
            i=0;
            f->val=sum;
        }
    }
    //最后检查进位是否是1,若是1则说明还有一位需要表示。创建结点来存放这个1。
    if(i==1){
      
        struct ListNode*d=(struct ListNode*)malloc(sizeof(struct ListNode));
        d->val=1;
        d->next=NULL;
        f->next=d;
    }
    //返回头结点的下一个结点
    return p->next;
}


附上 数据结构(严蔚敏)

typedef struct LNode  //单链表
{
	ElemType data;
	struct LNode* next;
}LNode, * LinkList_L;

/*
LinkList_L L;//定义链表L
LNode* P;LinkList_L p;//定义结点指针p
*/

//定义空的单链表
Status InitList_L(LinkList_L& L)
{
	L = new LNode;//c++语法
	L->next = NULL;
	return OK;
}

//判断单链表是否为空
Status ListEmpty_L(LinkList_L L)
{
	if (L->next)
		return 0;//不为空
	else 
		return 1;
}

//单链表的销毁
Status DestoryList_L(LinkList_L L)
{
	LNode *p;//LinkList_L p;
	while(L)
	{
		p = L;
		L = L->next;
		delete p;
	}
	return OK;
}

//单链表的清空
Status ClearList_L(LinkList_L &L)
{
	LNode *p, *q;
	p = L->next;
	while(p)
	{
		q = p->next;
		delete p;
		p = q;
	}
	L->next = NULL;
	return OK;
}

//求单链表的表长
Status ListLength_L(LinkList_L L)
{
	LNode* p;
	p = L->next; 
	int i=0;
	while (p)
	{
		i++;
		p = p->next;
	}
	return i;
}

//用e返回单链表第i个元素
Status GetElem_L(LinkList_L L, int i, ElemType e)
{
	LNode* p;
	p = L->next;
	int j = 1;//计数器
	while (p&&j<i)
	{
		p = p->next;
		++j;
	}
	if (!p||j>i) return ERROR;
	e = p->data;
	return OK;
}

// 在单链表L中查找值为e的元素
LinkList_L LocateElem_L(LinkList_L L, ElemType e)
{
	LNode* p;
	p = L->next;
	//返回地址
	while (p && p->data != e)
		p = p->next;
	return p;
}
//返回位置序号
Status LocateElem(LinkList_L L, ElemType e)
{
	LNode* p;
	p = L->next;
	int j = 1;
	while (p && p->data != e)
	{
		p = p->next;
		j++;
	}
	if (p)return j;
	else return 0;
}
//在第i个结点处插入新结点
Status ListInsert_L(LinkList_L& L, int i, ElemType e)
{
	LNode* p = L;
	int j = 0;
	while (p&&j<i-1)//找i-1结点
	{
		p = p->next;
		++j;
	}
	if (!p || j > i - 1)return ERROR;
	LNode* s;
	s = (LinkList_L)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return OK;
}

//删除单链表L第i个结点,并用e返回
Status ListDelete_L(LinkList_L& L, int i, ElemType e)
{
	LNode* p = L, * q;
	int j = 0;
	while (p->next && j < i - 1)//找i-1结点
	{
		p = p->next;
		++j;
	}
	if (!p->next || j > i - 1)return ERROR;
	q = p->next;//临时存放被删除的结点地址
	p->next = q->next;
	e = q->data;
	delete q;
	return OK;
}

//建立单链表L(头插-倒序)
void CreateList_L(LinkList_L &L,int n)
{
	L = new LNode;//建立带头节点的单链表
	L->next = NULL;
	LNode* p;
	for (int i=n;i>0;--i)
	{
		p = new LNode;//生成新结点p=(LNode*)malloc(sizeof(LNode));
		cin >> p->data;//scanf(&p->data);
		p->next = L->next;
		L->next = p;
	}
}//(尾插-正序)
void CreateList_R(LinkList_L& L, int n)
{
	L = new LNode;
	L->next = NULL;
	LNode* r;
	r = L;//尾指针r指向头指针
	LNode* p;
	for (int i = 0;i < n;++i)
	{
		p = new LNode;
		cin >> p->data;
		p->next = NULL;
		r->next = p;
		r = p;
	}
}

//应用
//有序表的合并(链式表示)
void MergeList_L(LinkList_L& La, LinkList_L& Lb, LinkList_L& Lc)
{
	LNode *pa,* pb, * pc;
	pa = La->next;
	pb = Lb->next;
	Lc = pc = La;//用La的头结点做Lc的头结点
	while (pa&&pb)
	{
		if (La->data <= Lb->data)
		{
			pc->next = pa;
			pc = pa;
			pa = pa->next;
		}
		else
		{
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
	}
	pc->next = pa ? pa : pb;
	delete Lb;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值