计算机中的三大结构:
直接前驱、该元素、直接后继
线性表存储
顺序表存储 优点: 快速访问
数组
链式存储 优点:大量删除、更新操作
链表
用typedef将结构体等价于 类型名Lnode,指针Linklist
typedef struct Lnode{ ElemType data; struct Lnode *next; }Lnode, *Linklist;
如果不这样写就要加上关键字struct来声明变量。
分配变量返回的是指针 s = new Lnode,则s是指针
链表的两种方式:
链表建立:
头指针不可以随意改动
STL List链表是双向链表
代码风格更加偏向工程化
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 << "\t"; 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.初始化\n"; 151 cout << "2.创建单链表(前插法)\n"; 152 cout << "3.创建单链表(尾插法)\n"; 153 cout << "4.取值\n"; 154 cout << "5.查找\n"; 155 cout << "6.插入\n"; 156 cout << "7.删除\n"; 157 cout << "8.输入\n"; 158 cout << "0.退出\n"; 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 << "初始化一个空的单链表!\n"; 169 } 170 break; 171 case 2: // 创建单链表(前插法) 172 CreateList_H(L); 173 cout << "前插法创建单链表输出结果:\n" << endl; 174 Listprint_L(L); 175 break; 176 case 3: // 创建单链表(尾插法) 177 CreateList_R(L); 178 cout << "尾插法创建单链表输出结果:\n" << 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 << "查找成功\n"; 186 cout << "第" << i << "个元素是:" << e << endl; 187 } else 188 { 189 cout << "查找失败\n" << 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 }
通过传递应用变量来获取返回值 e。
1 case 4: // 单链表的按序号取值 2 cout << "请输入一个位置用来取值:" << endl; 3 cin >> i; 4 if(GetElem_L(L, i, e)){ 5 cout << "查找成功\n"; 6 cout << "第" << i << "个元素是:" << e << endl; 7 } else 9 cout << "查找失败\n" << 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 }
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 << "\t"; 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 }
思路:快慢指针
链表长度为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 << "\t"; 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 }
原文:https://www.cnblogs.com/JCcodeblgos/p/11408173.html