线性表之链表的实现(一)-单链表带头结点实现

本文针对单链表,总结其相应的常用操作。主要是给出代码实现。

常量声明

common.h

#ifndef common_H
#define common_H

/* 函数结果状态码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
//#define OVERFLOW -2

/* 类型定义 */
typedef int Status;     // Status是函数的类型,其值是函数结果状态码
typedef int ElemType;   // ElemType是数据类型

#endif

链表节点结构及常用操作接口声明

LinkedList.h
注:以下常用操作接口均为带头结点的实现

#ifndef LinkedList_H
#define LinkedList_H
#include "common.h"
#include <cstdlib>

/* 链表节点声明 */
struct ListNode
{
    ElemType data;
    ListNode* next;

    ListNode() : data(0), next(NULL) {}
    ListNode( ElemType x ) : data(x), next(NULL) {}
};

typedef ListNode* LinkedList; // LinkedList是指向类型ListNode的指针



LinkedList create_by_head( const ElemType* arr, int n );    // 头插法 
LinkedList create_by_tail( const ElemType* arr, int n );    // 尾插法
Status destroy( LinkedList head );                          // 销毁
Status destroy1( LinkedList head );                         // 销毁 - 递归实现

Status print( LinkedList head );                        // 枚举
Status print1( LinkedList head );                       // 枚举 - 递归实现 - 调用函数时参数为head->next,避免处理头结点

Status insert_x( LinkedList head, ElemType x, int i );  // 在第i个位置进行插入
ElemType get( LinkedList head, int i );                 // 查找位于第i位的元素
Status delete_x( LinkedList head, ElemType x );         // 删除值为x的元素
Status delete_x_i( LinkedList head, int i );            // 删除位于第i个位置的元素

int get_length( LinkedList head );                      // 求单链表长度
bool increase( LinkedList head );                       // 判断单链表是否非递减
Status move_min( LinkedList head );                     // 移动最小值节点, 空间复杂度O(1)
Status min_out( LinkedList head );                      // 按非递减顺序输出单链表中元素,并释放节点所占的存储空间,空间复杂度O(1)
Status exchange( LinkedList head, LinkedList p );       // 交换节点p和p的后继

#endif
  • 头插法
    思路:头部插入,不需要额外指针。获得逆序序列。
LinkedList create_by_head( const ElemType* arr, int n )
{
    if( NULL == arr || n <= 0 )
    {
        std::cerr << "Invalid arguments!" << std::endl;
        return NULL;
    }

    LinkedList head = new ListNode();
    if( !head )
    {
        std::cerr << "Not enough space!" << std::endl;
        return NULL;
    }

    for( int i = 0; i < n; ++i )
    {
        LinkedList cur = new ListNode( arr[i] );
        if(!cur)
        {
            std::cerr << "Not enough space!" << std::endl;
            return NULL;
        }

        cur->next = head->next;
        head->next = cur;

    }

    return head;
}
  • 尾插法
    思路:需要维护一个尾部指针
LinkedList create_by_tail( const ElemType* arr, int n )
{
    if( NULL == arr || n <= 0 )
    {
        std::cerr << "Invalid arguments" << std::endl;
        return NULL;
    }

    LinkedList head = new ListNode();
    if( !head )
    {
        std::cerr << "Not enough space!" << std::endl;
        return NULL;
    }

    LinkedList tail = head;
    for( int i = 0; i < n; ++i )
    {
        LinkedList cur = new ListNode( arr[i] );
        if( !cur )
        {
            std::cerr << "Not enough space!" << std::endl;
            return NULL;
        }

        tail->next = cur;
        tail = cur;
    }

    return head;
}
  • 销毁
    思路:由于从头开始销毁会使链表断掉,所以,只能从尾部开始销毁。但是,单链表只能是从头部开始访问。所以如果直接写 O(N2) 的复杂度。换种思路,既然只能是从头开始访问,并且先访问的后销毁。显然会,这是一种“先进后出”的形式。考虑用栈做辅助数据结构。
Status destroy( LinkedList head )
{
    if(!head)
    {
        std::cerr << "Invalid arguments" << std::endl;
        return ERROR;
    }

    std::stack<LinkedList> stk;
    LinkedList p = head->next;
    while( p )
    {
        stk.push( p );
        p = p->next;
    }

    while( !stk.empty() )
    {
        delete stk.top();
        stk.pop();
    }

    return OK;
}
  • 销毁-递归实现
    思路:有了上面的思路,很自然过渡到递归的思路。本质还是用栈。
Status destroy1( LinkedList head )
{
    if( head )
    {
        destroy1( head->next );
        delete head;
    }
    return OK;
}
  • 打印
    思路:枚举
Status print( LinkedList head )
{
    if( !head )
    {
        std::cerr << "Invalid arguments" << std::endl;
        return ERROR;
    }
    LinkedList p = head->next;

    while( p )
    {
        std::cout << p->data << " "; 
        p = p->next;
    }
    std::cout << std::endl;

    return OK;
}
  • 打印-非递归
    思路:略。
    注意:
    参数传递时需要传递head->next
Status print1( LinkedList head )
{
    if( head )
    {
        std::cout << head->data << " ";
        print1( head->next );
    }
    return OK;
}
  • 在第i个位置插入
    思路:需要找到第i-1个位置。
    注意:第i个位置可能不存在
Status insert_x( LinkedList head, ElemType x, int i )
{
    if( NULL == head || i < 1 )
    {
        std::cerr << "Invalid arguments!" << std::endl;
        return ERROR;
    }

    LinkedList p = head->next;
    int j = 1;
    while( p && j < i - 1 )
    {
        p = p->next;
        ++j;
    }
    if( p )
    {
        LinkedList cur = new ListNode( x );
        if( !cur )
        {
            std::cerr << "Not enough space!" << std::endl;
            return ERROR;
        }

        cur->next = p->next;
        p->next = cur;
        return OK;
    }
    else
    {
        std::cerr << i << " is not exits!" << std::endl;
        return ERROR;
    }

}
  • 返回第i个位置的元素
    思路:略
    注意:第i个位置可能不存在
ElemType get( LinkedList head, int i )
{
    if( !head )
    {
        std::cerr << "Invalid arguments!" << std::endl;
        return ERROR;
    }

    LinkedList p = head->next;
    int j = 1;
    while( p && j < i )
    {
        p = p->next;
        ++j;
    }
    if(p)
    {
        return p->data;
    }
    else
    {
        std::cerr << i << " is not exits!" << std::endl;
        return ERROR;
    }
}
  • 删除第i个位置的元素
    思路:需要找到第i-1个位置的元素。维护一个pre指针即可。
    注意:第i个位置可能不存在
Status delete_x_i( LinkedList head, int i )
{
    if( !head )
    {
        std::cerr << "Invalid argumets!" << std::endl;
        return ERROR;
    }

    LinkedList pre = head;
    LinkedList p = head->next;
    int j = 1;

    while( p && j < i  )
    {
        pre = p;
        p = p->next;
        ++j;
    }
    if( p )
    {
        pre->next = p->next;
        delete p;
        p = NULL;
        return OK;
    }
    else
    {
        std::cerr << i << " is not exists! " << std::endl;
        return ERROR;
    }

}
  • 删除元素值为x的元素
    思路:需要找到x前面的一个元素,维护一个pre指针即可。
    注意:x可能不存在
Status delete_x( LinkedList head, ElemType x )
{
    if( !head )
    {
        std::cerr << "Invalid arguments!" << std::endl;
        return ERROR;
    }

    LinkedList pre = head;
    LinkedList p = head->next;
    while( p && p->data != x )
    {
        pre = p;
        p = p->next;
    }
    if( p )
    {
        pre->next = p->next;
        delete p;
        p = NULL;
        return OK;
    }
    else
    {
        std::cerr  << x << " is not exits!" << std::endl;
        return ERROR;
    }
}
  • 返回单链表长度
    思路:枚举
int get_length( LinkedList head )
{
    if( !head )
    {
        std::cerr << "Invalid arguments!" << std::endl;
        return -1;
    }

    int length = 0;
    LinkedList p = head->next;
    while( p )
    {
        ++length;
        p = p->next;
    }
    return length;
}
  • 判断单链表是否非递减
    思路:维护pre指针,枚举判断pre和当前元素值的大小。
bool increase( LinkedList head )
{
    if( !head )
    {
        std::cerr << "Invalid arguments!" << std::endl;
        return false;
    }

    LinkedList pre = head->next; // pre指向第一个节点
    if(!pre)
        return false;
    LinkedList p = pre->next;
    while( p )
    {
        if( pre->data > p->data )
            return false;
        pre = p;
        p = p->next;
    }
    return true; // 不存在逆序
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值