zoukankan      html  css  js  c++  java
  • 线性表 链表

    计算机中的三大结构:

    • 线形结构  不分叉
    • 树形结构
    • 图形结构

    直接前驱、该元素、直接后继

    线性表存储

    顺序表存储  优点: 快速访问

    数组

    链式存储  优点:大量删除、更新操作

    链表

    typedef将结构体等价于 类型名Lnode,指针Linklist

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

    如果不这样写就要加上关键字struct来声明变量。

    分配变量返回的是指针  s = new Lnode,则s是指针 

    链表的两种方式:

    • 头结点
    • 头指针

    链表建立:

    • 头插法 逆序建表   有头指针   没有标记的一端先修改,无标记的后修改。 两者都有标记修改哪一个无所谓。 指针只要一断,就找不到了。
    • 尾插法 正序建表   有尾指针

    头指针不可以随意改动

     STL List链表是双向链表

    代码风格更加偏向工程化 

     

    1、单链表操作

      1 #include <iostream>
      2 #include <string>
      3 #include <iomanip>
      4 #include <stdlib.h>
      5 
      6 using namespace std;
      7 
      8 typedef struct LNode{  // LNode为结构体的名字
      9     int data;  // 结点的数据域
     10     struct LNode *next;  // 结点的指针域
     11 }LNode, *LinkList;  // LinkList为指向结构体LNode的指针类型
     12 
     13 /*
     14  typedfs起别名的意思,给整个结构体起了个别名LNode, 指向结构体的指针*LinkList。
     15  */
     16 
     17 bool InitList_L(LinkList &L){  // 构造一个空的单链表L
     18     L = new LNode;  // 生成新节点作为头结点,用头指针L指向头结点
     19     /* 每次用new分配空间总会返回一个地址 */
     20     if(!L)
     21         return false;  // 生成节点失败
     22     L->next = NULL;  // 头结点的指针置为空
     23     return true;
     24 }
     25 
     26 void CreateList_H(LinkList &L){  // 头插法建立单链表  逆序
     27     // 输入n个元素的值,建立到头结点的单链表L
     28     int n;
     29     LinkList s;  // 定义一个指针变量
     30     L= new LNode;
     31     L->next= NULL;  // 先建立一个带头节点的空链表
     32     cout << "请输入元素个数n:" << endl;
     33     cin >> n;
     34     cout << "请以此输入n个元素:" << endl;
     35     cout << "前插法创建单链表..." << endl;
     36     while(n--){
     37         s = new LNode;  // 生成新结点
     38         cin >> s->data;  // 输入元素值给新节点的数据域
     39         s->next= L->next;
     40         L->next = s;  // 将新结点s插入到头结点之后
     41     }
     42 }
     43 
     44 void CreateList_R(LinkList &L){  // 尾插法创建单链表 正序
     45     // 输入n个元素的值,建立到带表头结点的单链表L
     46     int n;
     47     LinkList s, r;
     48     L = new LNode;
     49     L->next = NULL;  // 先建立一个带头结点的空链表
     50     r = L;  // 尾指针r指向头结点
     51     cout << "请输入元素个数n:" << endl;
     52     cin >> n;
     53     cout << "请以此输入n个元素:" << endl;
     54     cout << "尾插法创建单链表..." << endl;
     55     while (n--) {
     56         s = new LNode;  // 生成新结点
     57         cin >> s->data;  // 输入元素值赋值给新结点的数据域
     58         s->next = NULL;   // s就是最后一个
     59         r->next = s;  // 将新结点s插入尾结点*r之后
     60         r = s;  // r指向新的尾结点s
     61     }
     62 }
     63 
     64 bool GetElem_L(LinkList L, int i, int &e){  // 单链表的取值  e引用参数
     65     // 在带头结点的单链表L中查找第i个元素
     66     // 用e记录L中第i个元素的值
     67     int j;
     68     LinkList p;
     69     p = L->next;  // p指向第一个结点
     70     j = 1; // j为技术器
     71     while(j<i && p){  // 顺链域向后扫描,直到p指向第i个元素或者p为空
     72         p = p->next;  //p指向小一个结点
     73         j++;  // 计数器j相应加1
     74     }
     75     if(!p || j>i)
     76         return false;   // i值不合法i>n 或 i<=0
     77     e = p->data;
     78     return true;
     79     
     80 }
     81 
     82 bool LocateElem_L(LinkList L, int e){  // 按值查找
     83     //  在带头结点的单链表L中查找值为e的元素
     84     LinkList p;
     85     p = L->next;   // L指针不能动,会破坏链表
     86     while (p && p->data!=e)  // 顺链域向后扫描,直到p为空或p所指向结点的数据域等于e
     87     {
     88         p = p->next;   // p指向下一个结点
     89     }
     90     if(!p)
     91         return false;  // 查找失败p为NULL
     92     return true;
     93 }
     94 
     95 bool ListInsert_L(LinkList &L, int i, int e){  // 单链表的插入
     96     // 带头j结点的单链表L中第一个位置插入值为e的新结点
     97     int j;
     98     LinkList p, s;
     99     p = L;
    100     j = 0;
    101     while (p && j<i-1) {  // 查找第i-1个结点,p指向该结点
    102         p = p->next;
    103         j++;
    104     }
    105     if(!p || j>i-1)  // i>n+1 或者 i<1
    106         return false;
    107     s = new LNode;  // 生成新节点
    108     s->data = e;  // 将新节点的数据域置为e
    109     s->next = p->next;  // 将新结点的指针域指向节点ai
    110     p->next = s;  // 将结点p的指针域指向结点s
    111     return true;
    112 }
    113 
    114 bool ListDelect_L(LinkList &L, int i){  // 单链表的删除
    115     // 在带头结点的单链表L中,删除第i个位置
    116     LinkList p, q;
    117     int j;
    118     p = L;
    119     j = 0;
    120     while ((p->next) && (j<i-1))
    121     {
    122         p = p->next;
    123         j++;
    124     }
    125     if(!(p->next) || (j>i-1)){  // 当i>n 或i<1时,删除位置不合理
    126         return false;
    127     }
    128     q = p->next;   // 临时保存被删除节点的地址以被释放空间
    129     p->next = q->next; // 改变删除节点前驱结点的指针域
    130     delete q;   // 释放被删除结点的空间
    131     return true;
    132 }
    133 
    134 void Listprint_L(LinkList L) //单链表的输出
    135 {
    136     LinkList p;
    137     p = L->next;
    138     while (p)
    139     {
    140         cout << p->data << "	";
    141         p = p->next;
    142     }
    143     cout << endl;
    144     
    145 }
    146 
    147 int main(){
    148     int i, x, e, choose;
    149     LinkList L;
    150     cout << "1.初始化
    ";
    151     cout << "2.创建单链表(前插法)
    ";
    152     cout << "3.创建单链表(尾插法)
    ";
    153     cout << "4.取值
    ";
    154     cout << "5.查找
    ";
    155     cout << "6.插入
    ";
    156     cout << "7.删除
    ";
    157     cout << "8.输入
    ";
    158     cout << "0.退出
    ";
    159     choose = -1;
    160     while (choose != 0)
    161     {
    162         cout << "请输入数字选择:";
    163         cin >> choose;
    164         switch (choose)
    165         {
    166         case 1:
    167             if(InitList_L(L)){  // 初始化一个空的单链表
    168                 cout << "初始化一个空的单链表!
    ";
    169             }
    170             break;
    171         case 2: // 创建单链表(前插法)
    172             CreateList_H(L);
    173             cout << "前插法创建单链表输出结果:
    "  << endl;
    174             Listprint_L(L);
    175             break; 
    176         case 3: // 创建单链表(尾插法)
    177             CreateList_R(L);
    178             cout << "尾插法创建单链表输出结果:
    " << endl;
    179             Listprint_L(L);
    180             break;
    181         case 4:  // 单链表的按序号取值
    182             cout << "请输入一个位置用来取值:" << endl;
    183             cin >> i;
    184             if(GetElem_L(L, i, e)){
    185                 cout << "查找成功
    ";
    186                 cout << "" << i << "个元素是:" << e << endl;
    187             } else
    188             {
    189                 cout << "查找失败
    " << endl;
    190             }
    191             break;
    192         case 5:  // 单链表的按值查找
    193             cout << "请输入所要查找元素x" << endl;
    194             cin >> x;
    195             if(LocateElem_L(L,x))
    196                 cout << "查找成功" << endl;
    197             else
    198                 cout << "查找失败!" << endl;
    199             break;
    200         case 6:  // 单链表插入
    201             cout << "请输入出入的位置和元素(用空格隔开):";
    202             cin >> i;
    203             cin >> x;
    204             if(ListInsert_L(L, i, x))
    205                 cout << "插入成功" << endl;
    206             else
    207                 cout << "插入失败!" << endl;
    208             break;
    209         case 7:  // 单链表删除
    210             cout << "请输入所有删除的元素位置i:"  << endl;
    211             cin >> i;
    212             if(ListDelect_L(L, i))
    213                 cout << "当前单链表的数据元素分别为:" << endl;
    214                 Listprint_L(L);
    215                 cout << endl;
    216                 break;
    217         }
    218     }
    219     
    220     return 0;
    221 }
    View Code

     

    通过传递应用变量来获取返回值  e。

     1 case 4:  // 单链表的按序号取值
     2    cout << "请输入一个位置用来取值:" << endl;
     3    cin >> i;
     4    if(GetElem_L(L, i, e)){
     5        cout << "查找成功
    ";
     6        cout << "" << i << "个元素是:" << e << endl;
     7     } else 9         cout << "查找失败
    " << endl;11    break;
     1 bool GetElem_L(LinkList L, int i, int &e){  // 单链表的取值
     2     // 在带头结点的单链表L中查找第i个元素
     3     // 用e记录L中第i个元素的值
     4     int j;
     5     LinkList p;
     6     p = L->next;  // p指向第一个结点
     7     j = 1; // j为技术器
     8     while(j<i && p){  // 顺链域向后扫描,直到p指向第i个元素或者p为空
     9         p = p->next;  //p指向小一个结点
    10         j++;  // 计数器j相应加1
    11     }
    12     if(!p || j>i)
    13         return false;   // i值不合法i>n 或 i<=0
    14     e = p->data;
    15     return true;
    16     
    17 }

    2、两个非递减链表合并

    Lc辅助头指正   重复利用头结点

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 typedef struct LNode
     7 {
     8     int data; 
     9     struct LNode *next;
    10 }LNode, *LinkList;
    11 
    12 void CreateList_R(LinkList &L){
    13     int n;
    14     LinkList s, r;
    15     L = new LNode;
    16     L->next = NULL;
    17     r = L;
    18     cout << "请输入元素个数n:" << endl;
    19     cin >> n;
    20     cout << "请依次输入n个整型数(非递归):" << endl;
    21     cout << "尾插法创建单链表..." << endl;
    22     while (n--)
    23     {
    24         s = new LNode;
    25         cin >> s->data;
    26         s->next = NULL;
    27         r->next = s;  // 将新节点s插入尾结点r之后
    28         r = s; // r指向新的尾结点s
    29     }
    30 }
    31 
    32 void mergelinklist(LinkList La, LinkList Lb, LinkList &Lc){
    33     LinkList p, q, r;  // 结构体指针变量
    34     p = La->next;
    35     q = Lb->next;
    36     Lc = La;  // 这里Lc是没有创建的,而是直接借鉴La来创建链表
    37     r = Lc;  // r指向Lc的尾部
    38     while(p && q){
    39         if(p->data <= q->data){  // 把p指向的结点串起来
    40             r->next = p;
    41             r = p;
    42             p = p->next;  // p更新  p后移一个结点
    43         }else{
    44             r->next = q;
    45             r = q;
    46             q = q->next;  // q更新  q后移一个结点
    47         }
    48     }
    49     r->next = p ? p : q;
    50     delete Lb;
    51 }
    52 
    53 void Listprint_L(LinkList L){
    54     LinkList p;
    55     p = L->next;
    56     while (p)
    57     {
    58         cout << p->data << "	";
    59         p = p->next;
    60     }
    61     cout <<  endl;
    62     
    63 }
    64 
    65 
    66 int main(){
    67     LinkList La, Lb, Lc;
    68     cout << "创建有序(非递减)单链表La" << endl;
    69     CreateList_R(La);
    70     cout << "创建有序(非递减)单链表Lb" << endl;
    71     CreateList_R(Lb);
    72     mergelinklist(La, Lb, Lc);
    73     cout << "合并后的结果Lc:" << endl;
    74     Listprint_L(Lc);
    75     return 0;
    76 }
    View Code

    3、单链表 高效 取中间节点   

    思路:快慢指针

    链表长度为7 中间节点为4

    链表长度为6 中间节点为3

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 typedef struct LNode{
     6     int data;
     7     struct LNode *next;
     8 }LNode, *LinkList;
     9 
    10 void CreateList_R(LinkList &L){
    11     int n;
    12     LinkList s, r;
    13     L = new LNode;
    14     L->next = NULL;
    15     r = L;
    16     cout << "请输入元素个数n:" << endl;
    17     cin >> n;
    18     cout << "尾插法(正序)创建单链表..." << endl;
    19     while (n--)
    20     {
    21         s = new LNode;
    22         cin >> s->data;
    23         s->next = NULL;
    24         r->next = s;
    25         r =s;
    26     }
    27 }
    28 
    29 LinkList findmiddle(LinkList L){ // 快慢指针找中间元素
    30     LinkList fast, slow;
    31     fast = L;
    32     slow = L;
    33     while (fast!=NULL && fast->next!=NULL)
    34     {
    35         fast = fast->next->next;
    36         slow = slow->next;
    37     }
    38     return slow;
    39 }
    40 
    41 void Listprint_L(LinkList L){
    42     LinkList p;
    43     p = p->next;
    44     while (p)
    45     {
    46         cout << p->data << "	";
    47         p = p->next;
    48     }
    49     cout << endl;
    50 }
    51  
    52 int main(){
    53     LinkList L, mid;
    54     cout << "创建单链表L:" << endl;
    55     CreateList_R(L);
    56     mid = findmiddle(L);
    57     cout << "单链表中间节点数据为:" << mid->data << endl;
    58     return 0;
    59 }
    View Code
  • 相关阅读:
    eclipse svn插件
    eclipse 图片预览插件
    eclipse properties文件插件
    eclipse Failed to load the JNIshared library
    Spark MLlib之线性回归源代码分析
    ul,li不能左右居中的问题
    【日常学习】【搜索/递归】codevs2802 二的幂次方题解
    UVa 112
    查询一个月最后一天的总用户数,数据库中没有保存最好一天的数据,就查询本月数据库已存有的最后一天的数据
    uva:10763
  • 原文地址:https://www.cnblogs.com/JCcodeblgos/p/11408173.html
Copyright © 2011-2022 走看看