数据结构(复习)链表完结篇

关于链表我们其实有很多要学的东西,书上的东西其实都是皮毛,,只是引领我们而已,但是算法是一个积累的过程!!!

先把基础的东西学好吧!!

Coding-------------------------------------------------------------------------------------------------------------------

// 关于数据结构的总结与复习  Coding
//由于链表在空间上的合理利用和插入和删除不需要移动等优点,因此在很多时候,它是线性表
// 的首选储存结构。然而它的求长度的时候不如顺序储存结构来的好!!;另一方面由于链表中
//节点的关系用指针来表示,则数据元素在线性表的“位序”的概念已经淡化,而被数据元素的“位置”
// 代替, 所以我们从实际应用的情况下重新对它进行定义!!!!!!!

#include <cstdio>
#include <cstdlib>
//#define _OJ_
#define error 0
#define ok 1

typedef struct Lnode
{
    int data;
    struct Lnode *next;
} Lnode, *Link;

typedef struct Lnode1
{
    int len;                                //随时可测长度
    Link head, tail;                       //tail为哨兵节点
} Lnode1, *Linklist;

Linklist
Init_List(void)
{
    int i, n;
    Link p, head1;
    Linklist L;
    L = (Linklist) malloc (sizeof(Lnode1));
    L->head = (Link) malloc (sizeof(Lnode));
    L->tail = (Link) malloc (sizeof(Lnode));

    head1 = L->head;
    scanf("%d", &n);    L->len = n;
    for (i = 0; i < n; i++) {
        p = (Link) malloc (sizeof(Lnode));    scanf("%d", &p->data);
        L->head->next = p;
        L->head = p;
    }
    L->head->next = L->tail;
    L->head = head1;
    return L;
}

void
print(Linklist L)
{
    printf("打印链表:");
    while (L->head->next != L->tail) {
        printf("%d ", L->head->next->data);
        L->head = L->head->next;
    }
}


int main(int argc, char const *argv[]) {
#ifndef _OJ_ //ONLINE JUDGE
       freopen("input.txt", "r", stdin);
       //freopen("output.txt", "w", stdout);
#endif
    

    Linklist L;

    L = Init_List();

    printf("链表长度为:%d
", L->len);

    print(L);
    
    return 0;
}

  关于tail哨兵节点个人观点:

     1.在单链表中tail用NULL表示即可不需要重新申请空间;

     2.在非循环双链表中申请一个tail以便逆序访问;                                       tail->pre-------------------

     3.在循环双链表中不用尾节点                                                              不用null 也不用tial

-------------------------------------------------------------------------------------------------------------------------------------

1.链表逆序问题

思路一:

取出原始链表的第一个节点A,然后将该节点作为新链表的头节点。

现在状态为

原始链表:B->C->D->E

新链表:A

然后同上,变为了下面的状态

原始链表:C->D->E

新链表: B->A

原始链表:D->E

新链表: C->B->A

原始链表:E

新链表: D->C->B->A

原始链表:

新链表: E->D->C->B->A

很显然,对原始链表遍历一次,就完成了这个工作,所以这个算法的复杂度为O(n)。

1.这个思想很简单就是把链表遍历一遍采用逆序插入法插入到一个新的链表中去------------------在这儿不多说了!!!!!!!!!!!!!!!!!!!!

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

思路二:

2、 单链表逆序

         第二个题目是很经典的“单链表逆序”问题。很多公司的面试题库中都有这道题,有的公司明确题目要求不能使用额外的节点存储空间,有的没有明确说明,但是如果面试者使用了额外的节点存储空间做中转,会得到一个比较低的分数。如何在不使用额外存储节点的情况下使一个单链表的所有节点逆序?我们先用迭代循环的思想来分析这个问题,链表的初始状态如图(1)所示:

图(1)初始状态

 初始状态,prev是NULL,head指向当前的头节点A,next指向A节点的下一个节点B。首先从A节点开始逆序,将A节点的next指针指向prev,因为prev的当前值是NULL,所以A节点就从链表中脱离出来了,然后移动head和next指针,使它们分别指向B节点和B的下一个节点C(因为当前的next已经指向B节点了,因此修改A节点的next指针不会导致链表丢失)。逆向节点A之后,链表的状态如图(2)所示:

图(2)经过第一次迭代后的状态

 从图(1)的初始状态到图(2)状态共做了四个操作,这四个操作的伪代码如下:

head->next = prev;

prev = head;

head = next;

next = head->next;

这四行伪代码就是循环算法的迭代体了,现在用这个迭代体对图(2)的状态再进行一轮迭代,就得到了图(3)的状态:

图(3)经过第二次迭代后的状态

         那么循环终止条件呢?现在对图(3)的状态再迭代一次得到图(4)的状态:

图(4)经过第三次迭代后的状态

 此时可以看出,在图(4)的基础上再进行一次迭代就可以完成链表的逆序,因此循环迭代的终止条件就是当前的head指针是NULL。

        现在来总结一下,循环的初始条件是:

prev = NULL;

循环迭代体是:

next = head->next;

head->next = prev;

prev = head;

head = next;

循环终止条件是:

head == NUll

代码贴出如下:

// 关于数据结构的总结与复习  Coding
1.// 关于单链表逆序问题
#include <cstdio>
#include <cstdlib>
//#define _OJ_

typedef struct Lnode
{
    int data;
    struct Lnode *next;
} Lnode, *Linklist;

Linklist
Init_List(void)
//建立链表 { int i, n; Linklist L, p, head; L = (Linklist) malloc (sizeof(Lnode)); head = L; scanf("%d", &n); for (i = 0; i < n; i++) { p = (Linklist) malloc (sizeof(Lnode)); scanf("%d", &p->data); L->next = p; L = p; } L->next = NULL; return head; } //---------------------------------------------------------------------------------------------------------- Linklist trverser(Linklist L) { Linklist head, p, t, pre = NULL; //pre原始值为NULL head = L; L = L->next; //L跳过头结点从第一个元素开始 while (L != NULL) { t = L->next; L->next = pre; pre = L; L = t; } head->next = pre; //头结点下一个元素是最后一个节点 return head; } //-------------------------------------------------------------------------------------------------------------- void print(Linklist L) { Linklist p; p = L; printf("打印输出链表: "); while (p->next != NULL) { printf("%d ", p->next->data); p = p->next; } } int main(int argc, char const *argv[]) { #ifndef _OJ_ //ONLINE JUDGE freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); #endif Linklist L;
L = Init_List();
print(L);
L = trverser(L);
print(L); return 0; }

  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

二:关于单链表的排序问题

原文地址:https://www.cnblogs.com/airfand/p/5060987.html