链表相关例题

先说下使用链表应该注意什么:

1.因为链表是用指针表示的,所以进函数时候一定要判断head指针是否为NULL,在进行删除之后也要注意会不会链表为空了,如果调用一个NULL的指针会发生异常

2.无论增删改都要注意在头部跟在尾部两种情况,因为他们跟在中间的处理方法是不同的

3.增加要先连后断, 删除要先接后删

1.首先放最基础的创建、增删改

struct node
{
    int num;
    struct node *next;
    node(int x) : num(x), next(NULL){}
};
struct node* create() //直接按照输入顺序插入,如果想按照排序顺序直接在函数里调用Insert函数
{
    struct node *head = NULL, *p = NULL, *tail = NULL;
    int num, n, sz = sizeof(struct node);
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &num);
        p = (struct node *)malloc(sz)
        p->num = num;
        //顺序插入
        p->next = NULL;
        if(head == NULL)
            head = p;
        else
            tail->next = p;
        tail = p;
        /*
        逆序插入
        p -> next = head;
        head = p; //等于每次都在前面添加节点 第一个进来的是最后一个节点
        */
    }
    return head;
}
struct node* Insert(struct node *head, struct node *stud)
{
    struct node *pre = NULL, *buf, *cur;
    cur = stud;
    buf = head;
    if(head == NULL) //头结点插入
    {
        head = cur;
        head->next = NULL;
    }
    else  //这里逻辑一定要清晰
    {
        while((cur->num > buf->num && buf->next != NULL))
             pre = buf,buf = buf->next;
        if(cur->num <= buf->num)
        {
            if(buf == head) head = cur;
            else pre->next = cur;  //这时 buf指向原来head的地址,head指向cur的地址
            cur->next = buf;
        }
        else
            buf->next = cur, cur->next = NULL;
    }
}
struct node* Delete(struct node *head, int num)
{
    struct node *pre = NULL, *buf = NULL;
    if(head == NULL) return NULL;
    if(head->num == num)
    {
        pre = head;
        head = head->next;
        free(pre);
    }
    if(head == NULL) return NULL;//一定要看下删完了,是不是NULL,如果是NULL再调用会异常
    pre = head;
    buf = head->next;
    while(buf != NULL)
    {
        if(buf->num == num)
        {
            pre->next = buf->next;
            free(buf);
        }
        else
            pre = buf;
        buf = pre -> next;  //因为buf可能被释放,所以这里要是pre->next
    }
    return head;
}
void Print(struct node *head)
{
    if(head == NULL) return;
    struct node *cur;
    for(cur = head; cur!=NULL; cur = cur->next)
        printf("%d\n", cur->num);
}

2.在不知道头结点的情况下,如何删除一个已知节点

因为我们不知道头结点,所以根本不可能知道该节点之前节点的信息,只能知道之后的信息,而删除节点又必须是将前后两节点相连,所以我们只需要把要删除节点的下一个节点的信息都赋值给该节点,然后删除那个节点

node *p; // 当前节点
node *q;
q = p -> next;
p.data = q.data; // 复制q节点到p
p -> next = q -> next; // 删除q
free(q);

3.将链表逆序

思路:两个指针,一个往前进行头插入,另一个往后遍历获取结点,原来的头结点head不变,每次获取一个要前插的结点之后,将头节点跟获取的节点的下一个节点相连,把当前节点头插入到pre前面,更新pre的位置

vector<int> printListFromTailToHead(struct ListNode* head) 
{
        vector<int> vec;
        ListNode *buf=head;
        ListNode *pre=buf;
        if(head==NULL)
            return vec;
        while(head->next!=NULL)
        {
            buf=head->next;
            head->next=buf->next;
            buf->next=pre;            
            pre=buf;
        }
        while(buf)
        {
            vec.push_back(buf->val);
            buf=buf->next;
        }
        return vec;
}        

4.只遍历一遍链表,输出倒数第K个元素

2个指针,一开始都指向head,然后后面指针先往后k-1个位置,然后两者同时移动,后面指针到头了,前面指针就是倒数第k个位置,一定注意,链表题先看head是不是null,在删除以及移动过程中注意是不是null

 ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        struct ListNode *pre, *buf;
        if(pListHead == NULL) return NULL;
        pre = pListHead;
        buf = pListHead;
        k--;
        while(k--) 
        {
            buf = buf->next;
            if(buf == NULL) return NULL;
        }
        while(buf->next != NULL) buf = buf->next, pre = pre->next;
        return pre;
    }

5.合并两个有序的链表

这里一定记得函数开始先开 如果有一方是null怎么办,如果不在while前看,index可能会指针飞掉,因为可能当时index并没有赋值

ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        ListNode *index1, *index2, *index, *head;
        head = NULL;
        index1 = pHead1;
        index2 = pHead2;
        index = NULL;
        if(index1 == NULL) return index2;
        if(index2 == NULL) return index1;
        while(1)
        {
             if(index1->val <= index2->val) 
             {
                 if(head == NULL) head = index1, index = head;
                 else index -> next = index1, index = index->next;
                 index1 = index1->next;
             }
            else
            {
                if(head == NULL) head = index2, index = head;
                else index -> next = index2, index = index->next;
                index2 = index2 -> next;
            }
            if(index2 == NULL && index1 == NULL) break;
             if(index1 == NULL && index2 != NULL)
            {
                index->next = index2;
                break;
            }
             if(index2 == NULL && index1 != NULL)
            {
                index->next = index1;
                 break;
            }
        }
      return head;
    }

也可以写成递归的:

 ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1 == NULL) return pHead2;
        if(pHead2 == NULL) return pHead1;
        if(pHead1->val <= pHead2->val)
        {
            pHead1 -> next = Merge(pHead1->next, pHead2);
            return pHead1;
        }
        else 
        {
             pHead2 -> next = Merge(pHead1, pHead2->next);
            return pHead2;
        }
    }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值