数据结构复习之单链表:基本操作及逆序打印、逆转、合并等

本文详细介绍了二叉树数据结构的定义、基本操作及其应用,包括链表的初始化、长度计算、搜索、插入、删除和打印等操作,并提供了简洁高效的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树的定义

#include “stdafx.h”
#include<malloc.h>

struct ListNode;
typedef int ValueType;
typedef struct ListNode* ListNode;

/*
List是指向ListNode结构体首地址的指针,若定义List list,要使用list->value来访问结构体中的变量值,“->”运算符是取指针所指向的值。若定义struct ListNode list,则list只是个struct,访问成员变量value要使用list.value
*/
typedef ListNode List;  

//单链表,这里使用的链表没有专门的头节点,头结节点与其他节点一样,存有一个value
struct ListNode
{
    ValueType value;
    struct ListNode *next;    //VS2010中可省略这一行的struct
};

与上面等价、但更简洁的二叉树定义如下:

 typedef struct ListNode
{
    ValueType value;
    struct ListNode *next;    
}*ListNode, *List;

定义好数据结构之后,就可以写各种操作函数了:

 void nodeInit(ListNode node, ValueType value, ListNode next)
 {
     node->value=value;
     node->next=next;
 }

 int listLen(List list)
 {
     if(list==NULL)
         return 0;
     int len=1;
     ListNode p=list;
     while(p->next!=NULL)
     {
         len++;
         p=p->next;
     }
     return len;
 }

 //搜索简洁版:返回目标节点
 ListNode find1(List list, ValueType val)
 {
    if(list == NULL)
        return NULL;

    ListNode p=list;
    while(p->next!=NULL && p->value != val)
    {
        p=p->next;
    }
    if(p->next == NULL)
        return NULL;
    return p;
 }

 //find的另一版本:若找到则返回元素的位置序号(从0开始),否则返回-1
 int find2(List list,ValueType theValue)
 {
     if(list == NULL)
         return -1;
     ListNode* p;
     p=list;

     int position=0;
     int len=listLen(list);

     while(p->next != NULL && p->value != theValue)
     {
         position++;
         p = p->next;
     }
     if(position+1 ==len && p->value != theValue)
         return -1;
     return position;
 }

 //找到pos节点的前驱节点
 ListNode findPrev(List list, ListNode node)
 {
     ValueType val = node->value;
     int thePos=find(list,val);     //pos节点的位置
     if(list==NULL || thePos == -1 || thePos == 0)
         return NULL;

     ListNode p = list;
     ListNode q = p->next;
     while(q != NULL && q->value != val)
     {
         p = p->next;
         q = q->next;
     }
     return p;  //这是在保证pos节点存在于链表中且不是头节点的情况下才返回的
 }

//插入简洁版:在list中node节点后面插入inserted节点
void insert1(List list, ListNode node, ListNode inserted)
{
    if(list == NULL || node == NULL || inserted == NULL)
        return;

    ListNode p = list;
    while(p->value != node->value)
    {
        p = p->next;
    }
    if(p->value != node->value) //没找到
        return;
    if(p->next == NULL) //在表尾插入
        p->next = inserted;
    else
    {
        inserted->next = p->next;
        p->next = inserted;
    }
}

 //在链表list中下标为position的节点后面插入值value
 void insert2(List *listAddr, int position, ValueType value)
 {
     List newNode = (ListNode )malloc(sizeof(struct ListNode));
     if(newNode == NULL)
     {
         printf("分配内存出错");
         return;
     }
     newNode->value = value;

     if(*listAddr == NULL)
     {
         *listAddr = newNode;
         newNode->next = NULL;
         return;
     }

     ListNode temp=*listAddr;

     if(position < 0) //这时在链表最前面插入节点
     {
         *listAddr=newNode;
         newNode->next = temp;//(ListNode )temp;
     }
     else if(position+1 >= listLen(*listAddr))
     {
         while(temp->next != NULL)
         {
             temp = temp->next;
         }
         temp->next = newNode;
         newNode->next = NULL;
     }
     else
     {
         int i=0;
         while(i < position)
         {
             temp = temp->next;
             i++;
         }
         newNode->next = temp->next;
         temp->next = newNode;
     }
 }

 //删除节点
 void removeNode(List *list, ValueType value)
 {
     if(list == NULL || *list == NULL)
         return;

     ListNode pToBeDeleted = *list;
     if((*list)->value == value)
     {
         *list=(*list)->next;
         free(pToBeDeleted);
         pToBeDeleted = NULL;
     }
     else
     {
         ListNode pre;
         while(pToBeDeleted != NULL && pToBeDeleted->value != value)
         {
             pre=pToBeDeleted;
             pToBeDeleted = pToBeDeleted->next;
         }
         if(pToBeDeleted == NULL)
         {
             if(pre->value != value)    //value不在链表中
                 return;
             //value位于最后一个节点中
             pre->next = NULL;
             free(pToBeDeleted);
         }
         else
         {
             pre->next = pToBeDeleted->next;
             free(pToBeDeleted);
             pToBeDeleted = NULL;
         }
     }

 }

 //删除链表
 void removeList(List list)
 {
     ListNode p,temp;
     p=list;
     while(p != NULL)
     {
         temp=p->next;
         free(p);
         p=temp;
     }
     list = NULL;
 }

 //从尾到首打印节点值,这个方法会改变链表结构,不好
 void print(List list)
 {
     if(list == NULL)
         return;
     //int len=listLen(list);
     ListNode p,pre=NULL;
     p=list;

     while(p->next != NULL)
     {
         pre=p;
         p = p->next;
     }
     printf("\n%d",p->value);
     free(p);
     if(pre != NULL)
         pre->next = NULL;
     print(list);
 }

 //上面方法的改进版
 void printNodesReversing(List list)
 {
     if(list == NULL)
         return;
     if(list->next != NULL)
         printNodesReversing(list->next);
     printf("%d\n",list->value);
 }

 //快速删除节点:可在O(1)时间内完成(对于非尾节点)
 //可能会对头指针操作,所以list一定要用指向指针的指针!! 
 void fastDelet(List *list, ListNode toBeDeleted)
 {
     if(!list || !toBeDeleted)
         return;
     if(toBeDeleted->next == NULL)      //先处理特殊情况可能代码更容易写出来
     {
         //特殊情况:list只有一个节点
          if(*list == toBeDeleted)
         {
             free(*list);
             *list = NULL;
             toBeDeleted =NULL;
             return;
         }
         ListNode p = *list;
         ListNode pre = NULL;
         while(p->next != NULL)
         {
             pre = p;
             p = p->next;
         }
         pre->next = NULL;
         free(toBeDeleted);
         toBeDeleted = NULL;
     }
     else
     {
         ListNode next = toBeDeleted->next;
         toBeDeleted->value = next->value;
         toBeDeleted->next = next->next;
         free(next);
     }
 }

 //查找链表的倒数第k(k>=1)个节点
 ListNode findK(List list, int k)
 {
     int len = listLen(list);
     if(k < 1 || k > len)
         return NULL;
     ListNode p1 = list;
     ListNode p2 = list;
     int count = len;
     while(p1->next != NULL)
     {
         count--;
         if(count <= len - k)
         {
             p2 = p2->next;
         }
         p1 = p1->next;
     }
     return p2;
 }

 //链表逆转
 //解法1:从后往前逆转,递归依次找到最后一个节点。时间O(n^2)
 void reverseList1(List list, int length, List newList, ListNode lastNode)
 {
     //if(list == NULL)
     //   return;
     if(length <= 0)
         return;
     List reversed;
     ListNode p = list;
     ListNode pre = NULL;
     for(int i = 0; i < length; i++)
     {
         pre = p;
         p = p->next;
     }
     //if(pre == NULL)  //出口
     //  return;
     ListNode 
     newList = p;
     newList->next = pre;
     lastNode = pre;
    reverseList1(list, length-1, newList,lastNode->next);

 }

 //解法2:从前往后逆转,把断开的地方缓存起来。时间O(n)
 List reverseList2(List list)
 {
     if(list == NULL)
         return NULL;
     ListNode newHead = NULL;   //逆转之后的新表头
     ListNode lastNewHead;      //上一个表头
     ListNode p = list;
     while(p->next != NULL)
     {
         lastNewHead = newHead;
         newHead = p;
         newHead->next = lastNewHead;

         p = p->next;
     }
     lastNewHead = newHead;
     newHead = p;
     newHead->next = lastNewHead;

     return newHead;
 }

 //合并两个有序链表仍保持有序,这里以升序为例
 //方法1:归并排序中有序数组的合并思想,但需要定义好几个指针,比较麻烦,且容易出错
 List mergeLists1(List list1, List list2)
 {
     if(list1 == NULL)
         return list2;
     if(list2 == NULL)
         return list1;

     List newList = NULL;
     ListNode p1 = list1;
     ListNode p2 = list2;
     ListNode lastNode = NULL;  //合并的链表尾节点

     if(p1->value <= p2->value)
     {
         newList = p1;
         lastNode = p1;
         p1 = p1->next;
     }
     else
     {
         newList = p2;
         lastNode = p2;
         p2 = p2->next;
     }

     while(p1 != NULL && p2 != NULL)
     {
         ListNode temp = NULL;
        if(p1->value <= p2->value)
        {
            temp = p1->next;
            lastNode->next = p1;
            p1 = temp;
        }
        else
        {
            temp = p2->next;
            lastNode->next = p2;
            p2 = temp;
        }
        lastNode = lastNode-> next;
     }

     if(p1 != NULL)
         lastNode->next = p1;
     if(p2 != NULL)
         lastNode->next = p2;

     return newList;
 }

//方法2:利用递归,简洁明了
ListNode mergeLists2(List l1, List l2)
{
    if(l1 == NULL)
        return l2;
    if(l2 == NULL)
        return l1;

    ListNode newList;   
    ListNode temp;

    if(l1->value <= l2->value)
    {
        temp = l1->next;    //要断开l1,先缓存
        newList = l1;
        newList->next = mergeLists2(temp, l2);
    }
    else
    {
        temp = l2->next;
        newList = l2;
        newList->next = mergeLists2(l1, temp);
    }
    return newList;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值