单链表的实现

本文详细介绍了使用C++实现链表的基本操作及算法,包括初始化、销毁、头插、尾插、弹出、查找、排序、反转、判断环形链表等功能,并提供了完整的代码实现。

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE     (1)
#define FALSE    (0)
#define ZERO     (0)
#define ONLY_ONE (1)
typedef unsigned char Boolean;
typedef struct list{
    struct node *head;
    struct node *tail;
    int         count;
}*List;
typedef struct node{
    int          data;
    struct node *next;
}*p_node;
static void *Malloc(size_t length);
List init_list(void);
void destroy(List *list);
Boolean push_front(List list,int value);
Boolean push_back(List list,int value);
Boolean pop_front(List list);
Boolean pop_back(List list);
void sort_list_ascend(List list);
void sort_list_descent(List list);//节点由大到小排列
List merge_two_lists(List list1,List list2);
List merge_two_lists_recure(List list1,List list2);
p_node find_revise_node(List list,int num);//找到链表的倒数第num个节点
p_node find_mid_node(List list);
List reverse_list(List list);//逆置链表
void reverse_show_list(List list);
List list_dump(List list);//拷贝链表
Boolean is_list_intersect(List list1,List list2);//判断链表是否相交
p_node get_common_node(List list1,List list2);
void delete_one_node(List list,int value);//O(1)时间复杂度删除节点
Boolean has_circle(List list);//判断是否有环
p_node find_circle_first_node(List list);//找到环的第一个节点
void swap(p_node p,p_node q);
//接口实现
/////////////////////////////////////////////////////////////////
<pre name="code" class="cpp">//模块化思想,Malloc函数里,分配内存,顺便判断是否分配成功
static void *Malloc(size_t length)
{
    void *result;
    result = malloc(length);
    if(result == NULL){
        fprintf(stderr,"the stack is full");
        return ;
    }
}
//初始化链表
List init_list()
{
    List list;
    list = (List)Malloc(sizeof(struct list));
    bzero(list,sizeof(struct list));
    return list;
}
//销毁链表
void destroy(List *list)
{
    if(list == NULL && *list == NULL){
        return ;
    }
    //删除节点信息
    while((*list)->count){
        pop_front(*list);
    }
    free(*list);
    *list = NULL;
    //p_node p = (*list)->head;
    //while((*list)->head != (*list)->tail){
    //    (*list)->head = p->next;
    //    bzero(p,sizeof(struct list));
    //    p = (*list)->head;
    //}
    //bzero((*list),sizeof(struct list));
}
//头插法
Boolean push_front(List list,int value)
{
    if(list == NULL){
        return FALSE;
    }
//要插入的节点p
    p_node p = (p_node)Malloc(sizeof(struct node));
    p->data = value;
//链表节点为0时,首尾都等与节点p
    if(list->count == ZERO){
        p->next = NULL;
        list->tail = list->head = p;
//p插入到头指针前,然后另头指针指向p
   }else{
        p->next = list->head;
        list->head = p;
    }
    list->count++;
    return TRUE;
}
//尾插法
Boolean push_back(List list,int value)
{
    p_node p;
    if(list == NULL){
        return FALSE;
    }
    p = (p_node)Malloc(sizeof(struct node));
    if(list->count == ZERO){
        p->data = value;
        p->next = NULL;
        list->tail = list->head = p;
    }else{
        p->data = value;
        p->next = NULL;
        list->tail->next = p;
        list->tail = p;
    }
    list->count++;
    return TRUE;
}
//头部弹出
Boolean pop_front(List list)
{
    if(list->head == NULL||list->count == 0){
        return FALSE;
    }
    p_node p;
//如果只有一个节点,那么head和tail都置空
    if(list->count == ONLY_ONE){
        p = list->head;
        list->head = list->tail = NULL;
    }else{
//让p指向head,然后head指向head->next
        p = list->head;
        list->head = list->head->next;
    }
//释放p
    free(p);
    list->count--;
    return TRUE;
}
//尾部弹出
Boolean pop_back(List list)
{
    if(list->head == NULL||list->count == 0){
        return FALSE;
    }
    p_node tmp;
    p_node p = list->head->next;
    if(p->next == NULL){
        p = list->head;
        list->head = list->tail = NULL;
        list->count--;
        return TRUE;
    }
    while(p->next->next){
        p = p->next;
    }
    tmp = p->next;
    p->next = NULL'
    free(p);
    list->tail = p;
    list->count--;
    return TRUE;
}
//输出链表信息
void show_list(List list)
{
    p_node p = list->head;
    if(list != NULL && list->count != ZERO){
        while(p){
            printf("%d ",p->data);
            p = p->next;
        }
    }
    printf("\n");
}

//判断是否有环
Boolean has_circle(List list,p_node *p)
{
    if(list == NULL || list->count == 1){
        return FALSE;
    }
//分别定义快慢指针,快指针跑得速度是慢指针的两倍
    p_node fast_node = list->head;
    p_node slow_node = list->head;
    for(;;){
        fast_node = fast_node->next->next;
        slow_node = slow_node->next;
//如果快慢指针相遇,那么说明相交
        if(fast_node == slow_node){
            *p = fast_node;
            return TRUE;
        }
        else if(fast_node == NULL || fast_node->next == NULL)
            return FALSE;
    }
}
void delete_one_node(List list,int value)//O(1)时间复杂度删除节点
{
//把当前节点数据域和它的下一个节点互相交换,然后删除下一个节点
    p_node p = list->head->next;
    if(list == NULL){
        return ;
    }
    while(p->data != value && p){
        p = p->next;
    }
    if(p != list->tail){
        p->data = p->next->data;
        p->next = p->next->next;
    }
    else
        pop_back(list);
    list->count--;
}
 <img src="https://img-blog.youkuaiyun.com/20151127230018948?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
//找到两个链表的交点.两个节点数量相减得x,然后另链表节点数量多的跑x个单位,然后两者一起跑
p_node get_common_node(List list1,List list2)
{
    p_node p = list1->head;
    p_node q = list2->head;
    int c;
    if(!is_list_intersect(list1,list2)){
        return NULL;
    }
    if(list1->count > list2->count){
        c = ((list1->count) - (list2->count));
        while(c--){
            p = p->next;
        }
    }
    else{
        c = ((list2->count) - (list1->count));
        while(c--){
            q = q->next;
        }
    }
    while(p != q){
        p = p->next;
        q = q->next;
    }
    return p;
}
//两者尾节点相同说明相交
Boolean is_list_intersect(List list1,List list2)//判断链表是否相交
{
    if(list1 == NULL || list2 == NULL)
        return FALSE;
    return list1->tail == list2->tail;
}
//递归输出节点信息,当p->next为NULL时停止
static void rev_show_node(p_node p)
{
    if(p->next != NULL){
        rev_show_node(p->next);
    }
    printf("%d ",p->data);
}
//调用rev_show_node输出链表信息
void reverse_show_list(List list)
{
    if(list == NULL)
        return ;
    rev_show_node(list->head);
}

//通过判断是否是环二级指针得到交点intersect,把从intersect开始作为一个单链表,//从head开始到intersect作为第二个单链表//调用相交函数get_common_node得到相交节点

p_node find_circle_first_node(List list)//找到环的第一个节点{
//
List list2; List list1; p_node p = list->head; p_node intersect = NULL;
//判断是否有环,并且找到快慢指针交点
 has_circle(list,&intersect); if(list == NULL){ return NULL; }
//把环放入链表1中
 while(intersect->next != intersect){ push_front(list1,intersect->data); intersect = intersect->next; }
 push_front(list1,intersect->data);
//从头节点到快慢指针交点放入链表2中
 while(p != intersect){ push_front(list2,p->data); p = p->next; }
//找到要求节点
return get_common_node(list1,list2);}

//翻转链表,新建一个链表,然后头插
List reverse_list1(List list)//逆置链表{
//链表节点p等于链表头
p_node p = list->head; if(list == NULL || list->count < 2) { return NULL; } List L; L = init_list(); while(p){
//每次都是用原始链表节点的下一个,做新链表的头节点
 push_front(L,p->data); p = p->next; }
  return L;}
//把控制信息拷贝,然后通过memcpy拷贝数据域和链域
List list_dump(List list)//拷贝链表
{ 
    List L = (List)Malloc(sizeof(struct list));
    p_node q = NULL; 
    p_node p = list->head->next; 
    while(p != list->tail){ 
        q = (p_node)Malloc(sizeof(struct node)); 
        L->head = list->head; 
        L->count = list->count; 
        p = list->head->next; 
        q = L->head->next; 
        memcpy(p,q,sizeof(struct list)); 
    } 
    memcpy(L->tail,q,sizeof(struct list)); 
    return L;
}
//前两个节点要分开逆置,先把head赋给tail,然后另p赋给head
List reverse_list(List list)//逆置链表
{ 
    if(list->count == 1 || list == NULL){
        return NULL; 
    } 
    p_node p = list->head->next; 
    p_node q = p->next; 
    p_node q_next = NULL; //先把头节点和第二个节点逆置 
    p->next = list->head; 
    list->head->next = NULL; 
    list->tail = list->head; 
    if(q == NULL) 
        return list; 
    if(q){
        q_next = q->next; 
    }  
    while(q){ 
        q->next = p; 
        p = q; 
        q = q_next;
        if(q == NULL){ 
            break; 
        } 
        else 
            q_next = q_next->next; 
    } 
    list->head = p; 
    return list;
}
//swap的泛型编程,(unsigned long)&(((p_node)0)->next)表示链表的数据域的长度
void swap(p_node p,p_node q)
{
    p_node tmp = (p_node)Malloc(sizeof(struct node)); 
    memcpy(tmp,p,(unsigned long)&(((p_node)0)->next)); 
    memcpy(p,q,(unsigned long)&(((p_node)0)->next)); 
    memcpy(q,tmp,(unsigned long)&(((p_node)0)->next));
}
//冒泡排序,从头节点开始与它的后面所有节点做比较,如果它的下一个结构体数据域小于它,那么二者交换.然后头节点增加一个单位,以此类推直到倒数第二个节点.
void sort_list_ascend(List list)//节点由小到大排列
{
    if(list == NULL){
        return ; 
    } 
    p_node p = list->head; 
    p_node q = p->next; 
    while(p->next){ 
        while(q){ 
        if(p->data > q->data){ 
            swap(p,q); 
        } 
    q = q->next;  
    } 
    p = p->next; 
    q = p->next; 
    }
}
//与从小到大相似
void sort_list_descent(List list)//节点由大到小排列
{ 
    if(list == NULL){
        return ; 
    } 
    p_node p = list->head; 
    p_node q = p->next; 
    while(p->next){ 
        while(q){ 
            if(p->data < q->data){ 
                swap(p,q); 
            } 
        q = q->next; 
        } 
    p = p->next; 
    q = p->next; 
    }
}
//快慢指针,一个指针是另一个的一倍,当快指针的下一个或者它本身是NULL时,那么慢指针就是中点.
//无论奇偶,都是第n/2个
p_node find_mid_node(List list)
{ 
    p_node p = list->head; 
    p_node q = list->head; 
    while(p->next && p->next->next){ 
        p = p->next->next; 
        q = q->next; 
    } 
    return q;
}
//找到倒数第num个节点
p_node find_revise_node(List list,int num){
//跑num次p = p->next.然后p和q一起跑,当p为空时,说明q就是在倒数第num上
    p_node p = list->head; 
    p_node q = list->head; 
    if(list == NULL || num == 0){
        return NULL; 
    } 
    while(num--){ 
        p = p->next; 
    } 
    while(p){ 
        q = q->next;
        p = p->next; 
    } 
    return q;
}
int main(int argc,char *argv[]){ 
    List list;
    List L; 
    list = init_list(); 
    int i = 0; 
    for(;i < 10;++i){ 
        push_front(list,rand()%30); 
    } 
    sort_list_ascend(list); 
    show_list(list); 
    delete_one_node(list,2 show_list(list); 
    //L = reverse_list1(list); 
    //show_list(L); 
    //reverse_show_list(list); 
    destroy(&list); 
    //destroy(&L); 
    //List list1; 
    //List list2;
    //int i = 0;
    //list1 = init_list();
    //list2 = init_list();
    //for(;i < 10; ++i){ 
       // push_front(list1,rand()%200); 
    //} 
    //for(i = 0;i < 10; ++i){
      // push_front(list2,rand()%200); 
    //}
    //sort_list_ascend(list1); 
    //sort_list_ascend(list2);
    //show_list(list1);
    //show_list(list2); 
    //list = merge_two_lists(list1,list2); 
    //show_list(list); 
    //p_node p; //p_node q; 
    //int i = 0; 
    //for(;i < 10; ++i){ 
        // push_front(list,(rand())%50); 
    //} 
    //show_list(list);
    //p = find_revise_node(list,2); 
    //printf("%d\n",p->data); 
    //q = find_mid_node(list);
    //printf("%d\n",q->data);
    //sort_list_ascend(list);
    //list = reverse_list(list);
    //show_list(list);
    //destroy(&list); 
      return 0;
}




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值