6-C/C++实现数据结构链表相关操作

本文代码分别包括:

头文件、创建链表等

1创建链表

第8题验证是否有环的创建链表

2遍历链表函数

3删除链表结点函数

4-1倒置链表函数-方法一改变指针指向

4-2倒置链表函数-方法二改变结点位置(头插法,断一个接一个)

5删除倒数第n个结点-快慢指针法

6合并两个有序链表

7两数相加

8判断链表中是否有环

*9求环的入口(较难,考试可能性小)

*10求环的长度

*11约瑟夫环-不包含头结点的环删除指定序列结点后相连

主函数


PART 1(自己写的):

准备代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

typedef struct ListNode{
    int data;
    struct ListNode *next;
}ListNode;

1创建链表

//1创建链表
ListNode *CreatList(){
    ListNode *H,*M,*N;                              //定义头结点指针H、向下链接结点指针M、新创建结点指针N
    int n,c;                                          //n为创建链表结点的个数,c为结点data值
    H = (ListNode *)malloc(sizeof(ListNode));       //分配一块LinkNode类型的内存空间做头结点
    H->next = NULL;                                 //头结点指针域指向空
    M = H;                                          //M先指向头结点

    printf("please input the number of nodes:");
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        N = (ListNode *)malloc(sizeof(ListNode));   //新创建子结点
        printf("please input %dth data:",i);
        scanf("%d",&c);                             //新创建结点data值
        N->data = c;
        M->next = N;                                //通过M指针将新结点链接进单链表
        M = N;                                      //M指向最后一个结点
    }
    M->next = NULL;
    printf("\n");
    return H;
}

第8题验证是否有环的创建链表

//第8题验证是否有环的创建链表
ListNode *CreatList2(){
    ListNode *H,*M,*N;
    int n,c;
    H = (ListNode *)malloc(sizeof(ListNode));
    H->next = NULL;
    M = H;

    printf("please input the number of nodes:");
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        N = (ListNode *)malloc(sizeof(ListNode));
        printf("please input %dth data:",i);
        scanf("%d",&c);
        N->data = c;
        M->next = N;
        M = N;
    }
    M->next = H->next->next;
    printf("\n");
    return H;
}

2遍历链表函数

//2遍历链表函数
void TraverseList(ListNode *pHead){
    ListNode *p = pHead->next;
    while(p != NULL)
    {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");
}

3删除链表结点函数

//3删除链表结点函数
void Del_Node(ListNode *pHead,int n){
    ListNode *p = pHead;                        //定义p指向头结点
    ListNode *q = pHead->next;                  //定义q总指向p的下一个结点,q指向待删除元素
    int i = 1;
    while((q != NULL) && (n>=1) && (i<=n-1))    //循环终止条件为第n-1个元素已经是最后一个元素或者n小于1或者已经查找到索删位置
    {
        p = p->next;
        q = q->next;
        i++;
    }
    if(q == NULL)
        p->next = NULL;
    else{
        p->next = q->next;
        free(q);
    }
}

4-1倒置链表函数-方法一改变指针指向

//4-1倒置链表函数-方法一改变指针指向
ListNode *ReverseList(ListNode *pHead){
    ListNode *p,*q,*r;                  //定义三个指针依次指向头结点后三个结点
    p = pHead->next;
    q = p->next;
    r = q->next;

    if(p == NULL || q == NULL)            //如果不存在结点或者只有一个结点,则不发生交换
        return NULL;
    while(r != NULL)                    //如果最后一个结点指向NULL,则不再需要向后移动指针
    {
        q->next = p;
        p = q;
        q = r;
        r = r->next;
    }
    q->next = p;                        //对最后两个结点进行倒叙
    pHead->next->next = NULL;           //将第一个结点指向NULL
    pHead->next = q;                    //用头结点连接链表第最后一个结点,完成倒叙
}

4-2倒置链表函数-方法二改变结点位置(头插法,断一个接一个)

//4-2倒置链表函数-方法二改变结点位置(头插法,断一个接一个)
ListNode *ReverseList2(ListNode * pHead){
    ListNode *p,*q;
    p = pHead->next;
    q = p->next;

    while(p != NULL && q != NULL)       //如果为空链表或者q指向空,表示无结点调整不再执行循环,注意此处为!=所以要用&&
    {
        p->next = q->next;              //将q结点摘出来插在头结点后
        q->next = pHead->next;
        pHead->next = q;
        q = p->next;                    //更新指针,使得q总指向要调整的结点,而p指针一直指向最小值
    }
    return pHead;
}

5删除倒数第n个结点-快慢指针法

//5删除倒数第n个结点-快慢指针法
ListNode *Del_FromEnd(ListNode *pHead,int n){
    ListNode *slow,*fast;
    slow = pHead;
    fast = pHead;

    if(n<1)                          //输入不合法返回
    {
        printf("wrong,can't do it!\n");
        return NULL;
    }
    while(fast->next != NULL && n)   //此处限制的无法删除头结点
    {
        fast = fast->next;
        n--;
    }
    while(fast->next != NULL)
    {
        slow = slow->next;
        fast = fast->next;
    }
    fast = slow->next;                  //复用fast指针指向删除的结点用于free
    slow->next = slow->next->next;
    free(fast);
    return pHead;
}

6合并两个有序链表

//6合并两个有序链表
ListNode *MergeOderList(ListNode *pHead1,ListNode *pHead2){
    ListNode *nHead = NULL;                                         //定义一个新的头结点
    ListNode *pMove = NULL;                                         //定义一个新的遍历指针
    if(pHead1->next == NULL) return pHead2;                         //如果有一个链表为空则返回另一个链表头
    else if(pHead2->next == NULL) return pHead1;

    if((pHead1->next->data) <= (pHead2->next->data))                //将第一个结点链入新链表的头结点
        nHead = pHead1;
    else
        nHead = pHead2;

    pHead1 = pHead1->next;                                          //从第一个结点开始
    pHead2 = pHead2->next;
    pMove = nHead;

    while((pHead1 != NULL) && (pHead2 != NULL))                     //循环对比数据域的值,用pMove指针连接
    {
        if((pHead1->data) <= (pHead2->data))
        {
            pMove->next = pHead1;
            pMove = pHead1;
            pHead1 = pHead1->next;
        }
        else
        {
            pMove->next = pHead2;
            pMove = pHead2;
            pHead2 = pHead2->next;
        }
    }

    if(pHead1 == NULL)                                              //最后一个结点链入
        pMove->next = pHead2;
    else if(pHead2 == NULL)
        pMove->next = pHead1;
    return nHead;
}

 


7两数相加

//7两数相加
ListNode *NumberAdd(ListNode *pHead1,ListNode *pHead2){
    ListNode *nHead = (ListNode *)malloc(sizeof(ListNode));     //创建头结点
    nHead->next = NULL;
    ListNode *pMove = nHead;                                    //设立一个移动指针用于链接后方结点
    int symbol = 0;                                             //进位标志
    pHead1 = pHead1->next;                                      //两个相加链表从第一个结点开始
    pHead2 = pHead2->next;

    while((pHead1 != NULL) || (pHead2 != NULL))                 //循环终止条件
    {
        int x = (pHead1 != NULL)? pHead1->data:0;               //长度不一致时将先为NULL的置为0以相加时可以得到数值
        int y = (pHead2 != NULL)? pHead2->data:0;
        int sum = x + y + symbol;


        ListNode *p = (ListNode *)malloc(sizeof(ListNode));     //创建结点

        if(sum>=10)
        {
            p->data = sum % 10;
            symbol = 1;
        }
        else
            {
                p->data = sum;
                symbol = 0;
            }
        pMove->next = p;                                        //使用pMove指针将每次新创建的结点p链进链表
        pMove = p;
        if(pHead1 != NULL) pHead1 = pHead1->next;               //两个链表向下遍历
        if(pHead2 != NULL) pHead2 = pHead2->next;
    }
    pMove->next = NULL;

    if(symbol>0)                                                //如果最后一位相加后有进位,需要单独再创建一个结点保存进位值
    {
        ListNode *p = (ListNode *)malloc(sizeof(ListNode));
        p->data = symbol;
        pMove->next = p;
        p->next = NULL;
    }
    return nHead;
}

8判断链表中是否有环

//8判断链表中是否有环
void IfCircle(ListNode *pHead){
    ListNode *slow = pHead,*fast = pHead;       //设置快慢指针,慢指针每次走1步,快指针每次走2步
    if(pHead->next == NULL)
        printf("NO NODE!!");
    while(fast != NULL && fast->next != NULL){
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
        {
            printf("I HAVE A CIRCLE!!\n");
            break;
        }
    }
}

*9求环的入口(较难,考试可能性小)

//*9求环的入口(较难,考试可能性小)
ListNode *CircleEntrance(ListNode *pHead){
    ListNode *slow = pHead,*fast = pHead,*Len = pHead;       //设置快慢指针,慢指针每次走1步,快指针每次走2步,再设置一个指针用于遍历头结点到入口距离
    int cot = 0;                                             //cot用来统计环入口距离头结点距离
    if(pHead->next == NULL)
        printf("NO NODE!!");

    while(fast != NULL && fast->next !=NULL)                //注意链表为奇数偶数时fast移动后指向的位置
    {
        slow = slow->next;
        fast = fast->next->next;
        /*分析:设头结点到环入口距离为a,环长为r,slow和fast相遇时slow在环中走过的距离为x。可得相遇时慢指针走过的长度为a+x,
        快指针走过的距离为(a+x+r),由于fast=2倍slow,可得a=r-x,而r-x也等于slow距离环入口的长度*/
        if(slow == fast)
        {
            printf("I HAVE A CIRCLE!\n");
            while(Len != slow)              //见分析,slow与fast相遇点到环入口的距离等于头结点到环入口的距离
            {
                Len = Len->next;
                slow = slow->next;
                cot++;
            }
            printf("The Circle Entrance is %dth Node!\n",cot);
            return Len;
        }
    }
    if(fast == NULL || fast->next == NULL)
        return NULL;
}

*10求环的长度

//*10求环的长度
int CircleLength(ListNode *pHead){
    ListNode *Head;
    ListNode *a = CircleEntrance(Head);
    ListNode *b = a->next;                  //b为环入口的下一位,用户验证走完一圈因为下面循环判断的时候不能相等,所以这里错一位
    int cot = 1;                                //cot用来统计环长

    if(a == NULL)
        return 0;

    while(b != a)                           //b=a时即为环长
    {
        b=b->next;
        cot++;
    }
    printf("Circle Length is %d\n",cot);
    return cot;
}

*11约瑟夫环-不包含头结点的环删除指定序列结点后相连

//*11约瑟夫环-不包含头结点的环删除指定序列结点后相连
void JosphCircle(ListNode *pHead,int n){
    ListNode *p = pHead->next;              //p指向第一个结点
    ListNode *Del = NULL;                   //删除结点指针
    int cot=0;                              //cot为统计环长
    while(pHead->next != NULL)
        {
            pHead = pHead->next;
            cot++;
        }
    pHead->next = p;                        //将链表变成环
    if(n>=cot) printf("Bad Man!!");         //删除序列大于环长则不存在约瑟夫环
    while(p->next != p)
    {
        for(int i=1;i<=n;i++)
            p = p->next;
        Del = p->next;
        printf("DELE Node Number is %d\n",Del);
        p->next = Del->next;
        free(Del);
        /*此方法不对的原因是删除的是不是p本身而是下一个元素?
        p->data = p->next->data;
        Del = p->next;
        p->next = Del->next;
        free(Del);*/
    }
}

主函数

int main()
{
    ListNode *chain,*chain1,*chain2;
    chain = CreatList();
    //Del_Node(chain,4);
    //ReverseList2(chain);
    //Del_FromEnd(chain,5);
    //chain1 = CreatList();
    //chain2 = CreatList();
    //chain = MergeOderList(chain1,chain2);
    //chain = NumberAdd(chain1,chain2);
    JosphCircle(chain,2);
    TraverseList(chain);
    //chain = CreatList2();
    //IfCircle(chain);
    //CircleEntrance(chain);
    //CircleLength(chain);

    return 0;
}

PART 2(西交无尽):

#include<stdio.h>
#include<stdlib.h>
#define null NULL
//Definition of ListNode
typedef struct list_node
{
	int data ; //数据域,用于存储数据
	struct list_node *next ; //指针,可以用来访问节点数据,也可以遍历,指向下一个节点
}ListNode;


//尾插法创建链表
ListNode *CreateList(int n)
{
    ListNode *head;
    ListNode *p,*pre;
    int i;
    head=(ListNode *)malloc(sizeof(ListNode));
    head->next=NULL;
    pre=head;
    for(i=1; i<=n; i++)
    {
        printf("input name of the %d data:",i);
        p=(ListNode *)malloc(sizeof(ListNode));

        scanf("%d",&p->data);
        pre->next=p;

        pre=p;
    }
    p->next = NULL;
    //p->next=head->next->next;
    return head;
}

//遍历链表函数
void TraverseList(ListNode *pHead)
{
    ListNode *p = pHead->next; //将头节点的指针给予临时节点p
    while(p != NULL)           //节点p不为空,循环
    {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");
    return ;
}


//删除链表节点函数
int Del_Node(ListNode *pHead,int back)
{
    int i = 0;
    int data;
    ListNode *_node = pHead;
    ListNode *pSwap;
    if ((back < 1) && (NULL == _node->next))
    {
        printf("删除失败!\n");
        return 0;
    }
    while(i < back-1)
    {
        _node = _node->next;
        ++i;
    }
    pSwap = _node->next;
    data = pSwap->data;
    _node->next = _node->next->next;
    free(pSwap);
    return data;
}


//倒置链表3
ListNode *node2(ListNode *pHead){
    pHead = pHead->next;
    ListNode *p = NULL;
    while(pHead){
        ListNode *nx = pHead->next;
        pHead->next = p;
        p = pHead;
        pHead = nx;
    }
    return p;
}


//倒置链表1
ListNode *node1(ListNode *pHead){
    ListNode *p = NULL;
    ListNode *q = NULL;
    ListNode *r = NULL;
    if(pHead->next == NULL){return NULL;}
    if(pHead->next->next == NULL){return pHead;}
    else if(pHead->next->next->next == null) {
    p = pHead->next;
    q = p->next;
    q->next = p;
    pHead->next = q;
    p->next = NULL;
    }
    else if(pHead->next->next->next != null){

    p = pHead->next;
    q = p->next;
    r = q->next;
    p->next = null;
    while(r != NULL){
    q->next = p;
    p = q;
    q = r;
    r = r->next;
    }
    q->next = p;
    pHead->next = q;
    }
    return pHead;

}


//倒置链表3
ListNode* ReverseList(ListNode* pHead)
{
    ListNode *q=pHead->next;
    ListNode *p=NULL;
    ListNode *r=NULL;
    if(pHead->next==NULL)
        return NULL;
    while(q->next)
    {
        r=q->next;
        q->next=p;
        p=q;
        q=r;
    }
    q->next=p;
    pHead->next = q;
    return pHead;
}


//删除倒数第N个节点
ListNode *removeNthFromEnd(ListNode *head, int n)
{
    // write your code here
    ListNode *fast = head;
    ListNode *low  = head;
    ListNode *pre = NULL;

    if(head == NULL  || n <= 0)
    {
        return NULL;   //输入的链表为空,或输入的n不合法;
    }

    for(int i = 0; i < n-1; i ++)
    {
        if(fast->next)
        {
            fast = fast->next;
        }

        else
        {
            return NULL;   //输入的n大于链表的长度;
        }

    }

    while(fast->next)
    {
        fast = fast->next;
        pre  = low;      //需要保存需要删除的那个结点的上一个结点。
        low  = low->next;
    }

    if(low == head)   //删除的那个结点是头结点。
    {
        head = head->next;
    }
    else
    {
        pre->next = pre->next->next;
    }

    return head;
}


//合并两个有序链表
ListNode *MergeTwoOrderedLists(ListNode *pHead1, ListNode *pHead2)
{
    ListNode *pTail = NULL;//指向新链表的最后一个结点 pTail->next去连接
    ListNode *newHead = NULL;//指向合并后链表第一个结点

    if (pHead1->next == NULL)
    {
        return pHead2;
    }
    else if(pHead2->next == NULL)
    {
        return pHead1;
    }
    else
    {
        //确定头指针
        if ( pHead1->next->data < pHead2->next->data)
        {
            newHead = pHead1;
        }
        else
        {
            newHead = pHead2;
        }
            pHead1 = pHead1->next;
            pHead2 = pHead2->next;
        pTail = newHead;    //指向第一个结点
        while ( pHead1 && pHead2)
        {
            if ( pHead1->data <= pHead2->data )
            {
                pTail->next = pHead1;
                pHead1 = pHead1->next;
            }
            else
            {
                pTail->next = pHead2;
                pHead2 = pHead2->next;
            }
            pTail = pTail->next;
        }

        if(pHead2 != NULL)
        {
            pTail->next = pHead2;
        }
        else if(pHead1 != NULL)
        {
            pTail->next = pHead1;
        }
        return newHead;
    }
}


//两数相加
ListNode *addTwoNumbers(ListNode *pHead1, ListNode *pHead2) {
    ListNode *L,*curr;
    L = (ListNode *)malloc(sizeof(ListNode));
    L->next = NULL;
    curr = L;
    ListNode *p = pHead1->next, *q = pHead2->next;
    int carry = 0;
    while (p != null || q != null) {
        int x = (p != null) ? p->data : 0;
        int y = (q != null) ? q->data : 0;
        int sum = carry + x + y;
        carry = sum / 10;
        ListNode *r = (ListNode *)malloc(sizeof(ListNode));
        r->data = sum%10;
        curr->next = r;
        curr = curr->next;
        if (p != null) p = p->next;
        if (q != null) q = q->next;
    }
        curr->next = NULL;
    if (carry > 0) {
        ListNode *r = (ListNode *)malloc(sizeof(ListNode));
        r->data = carry;
        curr->next = r;
        curr->next->next = NULL;
    }
    return L;
}

//检查环
int HasCircle(ListNode * pHead)
{
    ListNode * pFast = pHead; // 快指针每次前进两步
    ListNode * pSlow = pHead; // 慢指针每次前进一步
    while(pFast != NULL && pFast->next != NULL)
    {
        pFast = pFast->next->next;
        pSlow = pSlow->next;
        if(pSlow == pFast) // 相遇,存在环
            return 1;
    }
    return 0;
}

//找出环的入口
ListNode  *searchEntranceNode(ListNode *pHead)
{
    ListNode *pSlow=pHead;//p表示从头结点开始每次往后走一步的指针
    ListNode *pFast=pHead;//q表示从头结点开始每次往后走两步的指针
    while(pFast !=NULL && pFast->next !=NULL)
    {
        pSlow=pSlow->next;
        pFast=pFast->next->next;
        if(pSlow == pFast){
            break;//p与q相等,单链表有环
        }
    }
    if(pFast==NULL || pFast->next==NULL)
        return NULL;

    pSlow=pHead;
    while(pSlow != pFast)
    {
        pSlow=pSlow->next;
        pFast=pFast->next;
    }
    return pSlow;
}

//求环长
int circleLength(ListNode *pHead)
{
    ListNode *p=searchEntranceNode(pHead);//找到环的入口结点
    if(p==null)
        return 0;//不存在环时,返回0
    ListNode *q = p->next;
    int length=1;
    while(p != q)
    {
        length++;
        q=q->next;
    }
    return length;//返回环的长度
}

//约瑟夫环
void JosephProblem(ListNode *pHead,int m){
    ListNode *p = pHead->next;
    while(pHead->next != NULL) pHead = pHead->next;
    pHead->next = p;

    while(p->next != p){
        for(int i = 0;i<m-1;i++) p=p->next;

        //打印
        printf("%d ",p->next->data);

        ListNode *del = p->next;
        p->next = del->next;
        free(del);
        /*
        //特殊的删除方法
        p->data = p->next->data;
        ListNode *del = p->next;
        p->next = del->next;
        free(del);
        */
    }
}

int main()
{
    ListNode *chain,*nchain,*nnchain,*nnnchain = NULL;
    int n,back2;
    chain = CreateList(5);
    JosephProblem(chain,2);
    return 0;
}

(感谢西交无尽学长提供以上题目练习)

快慢指针参考:http://www.cnblogs.com/hxsyl/p/4395794.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值