线性表的链式存储

      线性表的链式存储。主要是单链表的相关知识,介绍了正序建立单链表、逆序建立单链表、单链表的插入、删除、查找、输出以及单链表的合并方法。单链表的合并前提是两个都有序。具体知识点详见代码注释。

  1 /***
  2 线性表的链式存储结构不能随机存储,整个链表的存取都必须从头结点开始。但是没有顺序存储的缺点:插入或者删除时需要移动大量元素
  3 其特点是用一组任意的存储空间存储线性表的数据元素
  4 
  5 结点:数据域和指针域
  6 */
  7 #include<stdio.h>
  8 #include<stdlib.h>
  9 #define MAX 100000
 10 //**********************线性表的单链表存储结构***********************
 11 typedef struct LNode
 12 {
 13     int data;            //数据域
 14     struct LNode *next;  //指针域
 15 } LNode,*LinkList;       //LinkList是LNode型结构的指针
 16 
 17 
 18 //**************************头插法逆序建立单链表****************************
 19 void CreateList_L1(LinkList &L,int n)
 20 {
 21     //逆位序输入n个元素值,建立带有头结点的单链表,时间复杂度为O(n)
 22     L->next = NULL;//先建立个带有头结点的单链表L,使头结点指针域为空,
 23     for (int i = n; i > 0; --i)
 24     {
 25         LinkList p = (LinkList)malloc(sizeof(LNode));//生成新结点
 26         scanf("%d",&p->data);
 27         //插入到表头
 28         p->next = L->next;
 29         L->next = p;
 30     }
 31 
 32 }
 33 
 34 //**************************尾插法正序建立单链表****************************
 35 void CreateList_L2(LinkList &L,int n)
 36 {
 37     //借助一个中间变量,正序建立n个元素的单链表,时间复杂度仍然为O(n)
 38     //先建立个带有头结点的单链表L,头结点指针域为空,默认使用Linklist建立L是即为空
 39     LinkList r = L;
 40     for (int i = 0; i < n; ++i)
 41     {
 42         LinkList p = (LinkList)malloc(sizeof(LNode));//生成新结点
 43         scanf("%d",&p->data);
 44         //插入到表尾
 45         r->next = p;
 46         r = p;
 47     }
 48     r->next = NULL;
 49 }
 50 
 51 //**************************按序输出单链表的各个元素****************************
 52 void PrintList_L(LinkList L)
 53 {
 54     LinkList p = L->next;//p指向第一个元素
 55     while(p)
 56     {
 57         printf("%d ", p->data);
 58         p = p->next;
 59     }
 60 }
 61 
 62 //***********************取出指定位序的单链表中的数据元素***********************
 63 int  GetElem_L(LinkList L,int i)
 64 {
 65     //时间复杂度为O(n)
 66     //L为带头结点的单链表的头指针
 67     //返回链表的第i个元素,若没有,则错误提示
 68     LNode *p = L->next; //初始化,p指向第一个结点
 69     int j = 1;//计数器
 70     int e;//返回值
 71     while(p && j<i)
 72     {
 73         //顺指针向后查找,知道p指向第i个元素或者p为空
 74         p = p->next;
 75         ++j;
 76     }
 77     if (!p || j>i)
 78     {
 79         printf("没有找到该元素,请确认后重新输入位序!
");
 80         e = MAX;
 81         return e;
 82     }
 83     e = p->data;
 84     return e;
 85 }
 86 
 87 
 88 //*******************向单链表的指定位序插入一个元素********************
 89 void ListInsert_L(LinkList &L,int i,int e)
 90 {
 91     //在带头结点的单链表L的第i个位置之前插入元素e,1=<i<=length(L)+1,时间复杂度为O(n)
 92     /*
 93     LNode *p = L->next; //初始化,p指向第一个结点,下面一句话效果一样,因为LinkList是指向LNode型的指针变量,无需再加*号
 94     LinkList p = L->next;
 95     int j = 1;//计数器
 96     */
 97     //上面使p指向第一个结点的方法有问题,如果要将元素插在第一位会有bug,故要从头结点开始
 98     LinkList p = L;
 99     int j = 0;
100     while(p && j<i-1)
101     {
102         p = p->next; //寻找第i-1个结点,使p指向它
103         ++j;
104     }
105     if (!p || j>i-1)
106     {
107         printf("要插入的位置没有找到,可能是插入位序有误!
");
108         getchar();
109         exit(1);
110     }
111     LinkList s = (LinkList)malloc(sizeof(LNode));//生成一个结点s
112     s->data = e;
113     //插入结点
114     s->next = p->next;
115     p->next = s;
116 }
117 
118 //********************删除单链表的指定位序的一个元素********************
119 void ListDelete_L(LinkList &L,int i)
120 {
121     //时间复杂度为O(n)
122     //在带头结点的单链表L中,删除第i个位置的元素.i<=length(L)
123     LNode *p = L; //初始化,p指向头结点
124     int j = 0;//计数器
125     while(p->next && j<i-1)
126     {
127         p = p->next; //使p指向被删除结点的前一个结点,即p指向i-1
128         ++j;
129     }
130     if (!(p->next) || j>i-1)
131     {
132         //要保证p的后一个元素有值,即被删除元素存在
133         printf("删除位置不合理,请重新确认!
");
134         getchar();
135         exit(1);
136     }
137     //删除该元素
138     LNode *q = p->next;
139     p->next = q->next;
140     free(q);//释放结点
141 }
142 
143 //**************************有序链表的合并******************************
144 void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc)
145 {
146     //已知单链线性表La和Lb的元素按值非递减排序
147     //归并La和Lb得到新的单链表Lc,Lc的元素也按值非递减排列
148     LinkList pa,pb,pc;
149     pa = La->next;
150     pb = Lb->next;
151     //用La的头结点作为Lc的头结点
152     pc = La;
153     Lc = pc;
154     while(pa && pb)
155     {
156         if (pa->data <= pb->data)
157         {
158             pc->next = pa;
159             pc = pa;
160             pa = pa->next;
161         }
162         else
163         {
164             pc->next = pb;
165             pc = pb;
166             pb = pb->next;
167         }
168     }
169     pc->next = pa?pa:pb;
170     free(Lb);//释放Lb的头结点
171 }
172 
173 int main()
174 {
175     //定义3个链表,初始化3个头结点
176     LinkList la = (LinkList)malloc(sizeof(LNode));
177     LinkList lb = (LinkList)malloc(sizeof(LNode));
178     LinkList lc;//
179     int count;//计数使用,链表初始化时记录链表元素个数
180     int location,value;//插入时的位置和值
181     char c;
182     //使用头插法逆序建立链表
183     printf("请输入la链表元素个数:");
184     scanf("%d",&count);
185     CreateList_L1(la,count);
186     printf("逆序建立的la链表元素为:");
187     PrintList_L(la);
188 
189     //使用尾插法正序建立链表
190     printf("

请输入链表lb元素个数:");
191     scanf("%d",&count);
192     CreateList_L2(lb,count);
193     printf("正序建立的lb链表元素为:");
194     PrintList_L(lb);
195 
196     //向正序建立的单链表中插入数据
197     printf("

请输入lb插入位置和插入值:");
198     scanf("%d%d",&location,&value);
199     ListInsert_L(lb,location,value);
200     printf("插入元素之后的链表元素为:");
201     PrintList_L(lb);
202 
203     //继续测试该链表的删除效果
204     printf("

请输入lb删除位置:");
205     scanf("%d",&location);
206     ListDelete_L(lb,location);
207     printf("删除元素之后的链表元素为:");
208     PrintList_L(lb);
209 
210     //测试GetElem函数是否有效
211     printf("

请输入需要得到的元素位置:");
212     scanf("%d",&location);
213     value = GetElem_L(lb,location);
214     if (value == MAX)
215     {
216         printf("输入错误或者没有该位置的元素!
");      
217     }else
218     {
219         printf("该元素的值为:%d",value);
220     }
221 
222     //测试两个链表的归并,前提是两个链表都有序
223     MergeList_L(la,lb,lc);
224     printf("

两个链表合并后lc的元素是:");
225     PrintList_L(lc);
226 
227     return 0;
228 }
原文地址:https://www.cnblogs.com/wujiyang/p/4335237.html