有序链表的插入操作

C语言教材的有序单链表程序的插入我并不满意,因为链表为空,表尾等原因导致有四种情况要处理,给同学们的阅读造成困难。书上的做法较复杂的一个原因是链表是不带头结点的,所以要考虑新结点插入时会不会变成表头,

例如:当链表为空时, 插入3, 3变成表头,  再插入1, 链表为1->3, 链表头指向1, 代码必须处理这样的情况.

第一部分: 不含头结点的链表插入的非常规思路

下面我给出另外一个思路,新结点一律插入表头,这样就不要考虑链表为空的情况了。但是可能无序,可以从表头开始,相邻节点不符合次序要求交换即可,代码的逻辑非常简单,当然效率不高,因为交换(结构可能很大)的缘故。

例如 1->2,  插入3 构成 3->1->2, 先交换变成1->3->2,再交换变成1->2->3

下面是我简单的示例程序,附带说明了另外一个概念,插入的过程即是建表的过程。

 1 #include <stdlib.h>
 2 #include <stdio.h>
 3 #include <string.h>
 4 struct node    /*节点的数据结构*/
 5 {
 6     int num;
 7     char str[20];
 8     struct node *next;
 9 };
10 /* * * * * * * * * * *主函数 * * * * * * * * * * * * * * * * */
11 int main(void)
12 {
13     struct node *insert(struct node *head,char *pstr,int n);  /*函数声明 */
14     void print(struct node *head);  /*函数声明 */
15     struct node *head;
16     char str[20];
17     int i, n;
18     head=NULL;  /*做空表*/
19
20     for(i=0;i<5;i++){ //仅输入5组数据
21         printf("\n input inserted num name:\n"); // 号码 空格 姓名
22         scanf("%d", &n);
23         gets(str);  /*输入姓名*/
24         head=insert(head,str,n); /* 将节点插入链表*/
25         print(head);  /*调用函数输出节点*/
26     }
27     return 0;
28 }
29
30 /* * * * * * * * * * * * * * 插入节点函数* * * * * * * * * * * * * * * */
31 struct node *insert(struct node *head,char *pstr,int n) /*插入学号为n、姓名为pstr的节点*/
32 {
33     struct node *p;
34     p=(struct node*)malloc(sizeof(struct node)); /*分配一个新节点*/
35     strcpy (p->str,pstr);  /*写入节点的姓名字串*/
36     p->num=n;        /* 指向学号*/
37
38     /*新节点插入表头*/
39     p->next=head;
40     head=p;
41
42     while(p->next&&p->next->num<p->num)
43     {
44         //交换邻接结点p和p->next的值(但是保留结点的next)
45         struct node t;
46         struct node *pr=p->next, *pn=p->next->next;
47         t=*(p->next);
48         *(p->next) = *p;
49         p->next->next=pn;
50         *p = t;
51         p->next=pr;
52
53         p=p->next;
54     }
55     return(head);/* 返回链表的头指针*/
56 }
57
58
59 /* * * * * * * * * * * * * * 链表输出函数* * * * * * * * * * * * * */
60 void print (struct node *head)
61 {
62     struct node *temp;
63     temp=head;
64     printf("output strings:\n");
65     while (temp!=NULL)
66     {
67         printf("%d -- %s\n",temp->num,temp->str);
68         temp=temp->next;
69     }
70     return;
71 }

输入如下

input inserted num name:

1 zhang

output strings:

1 --  zhang

input inserted num name:

2 li

output strings:

1 --  zhang

2 --  li

input inserted num name:

3 zhao

output strings:

1 --  zhang

2 --  li

3 --  zhao

input inserted num name:

4 qian

output strings:

1 --  zhang

2 --  li

3 --  zhao

4 --  qian

input inserted num name:

5 chen

output strings:

1 --  zhang

2 --  li

3 --  zhao

4 --  qian

5 --  chen

第二部分:带头结点的做法,我们分配一个结点永远做为链表头, 这样的话新插入的结点总是在后面,就没有前面提到的烦恼了.

 1 #include <stdlib.h>
 2 #include <stdio.h>
 3 #include <string.h>
 4 struct node    /*节点的数据结构*/
 5 {
 6     int num;
 7     char str[20];
 8     struct node *next;
 9 };
10 /* * * * * * * * * * *主函数 * * * * * * * * * * * * * * * * */
11 int main(void)
12 {
13     void insert(struct node *head,char *pstr,int n);  /*函数声明 */
14     void print(struct node *head);  /*函数声明 */
15     struct node *head;
16     char str[20];
17     int i, n;
18     head=(struct node*)malloc(sizeof(struct node));  /*head指向头结点*/
19     head->next=NULL;
20
21     for(i=0;i<5;i++){ //仅输入5组数据
22         printf("\n input inserted num name:\n"); // 号码 空格 姓名
23         scanf("%d", &n);
24         gets(str);  /*输入姓名*/
25         insert(head,str,n); /* 将节点插入链表*/
26         print(head);  /*调用函数输出节点*/
27     }
28     return 0;
29 }
30
31 /* * * * * * * * * * * * * * 插入节点函数* * * * * * * * * * * * * * * */
32 void insert(struct node *head,char *pstr,int n) /*插入学号为n、姓名为pstr的节点*/
33 {
34     struct node *p;
35     p=(struct node*)malloc(sizeof(struct node)); /*分配一个新节点*/
36     strcpy (p->str,pstr);  /*写入节点的姓名字串*/
37     p->num=n;        /* 指向学号*/
38
39
40     /*寻找p的插入位置*/
41     while(head->next&&head->next->num<p->num)
42     {
43         head=head->next;
44     }
45
46     /*应该在head之后插入p*/
47     p->next=head->next;
48     head->next=p;
49 }
50
51
52 /* * * * * * * * * * * * * * 链表输出函数* * * * * * * * * * * * * */
53 void print (struct node *head)
54 {
55     struct node *temp;
56     temp=head->next;
57     printf("output strings:\n");
58     while (temp!=NULL)
59     {
60         printf("%d -- %s\n",temp->num,temp->str);
61         temp=temp->next;
62     }
63     return;
64 }

行18,19就是分配头结点并初始化, 头结点的data我们不用.

因为head不会改变, 第32行insert也没有必要返回值, 而且恰好弥补了书中接口设计的缺陷. 另外其实现大大简化了,也没有第一个部分的低效问题. 这里值得注意的是第41行head->next的做法,保证了p一定插在head 和head->next之间.

头结点的另外一个变化就是第56行,head->next才是第一个有效的数据结点.

有序链表的插入操作,布布扣,bubuko.com

时间: 2024-10-12 15:14:27

有序链表的插入操作的相关文章

带头节点的单链表的插入操作

1.偶然看到了十字链表的应用,想到之前在<数据结构与算法分析>的链表一章中,需要用多重表实现一个简单的查询功能.功能需求如下: “已知 学生 和 学校课程 总数 分别为 40000 和 2500,现在需要得到两份报告,一份显示每门课成注册的所有学生信息, 一份显示每个学生注册了哪些课程.” 显然可以用一个 40000 * 2500 个元素的二维数组来解决,但是每个学生选课数目很少,因此会浪费很多空间.因此选择十字链表来实现. 既然是链表,那么肯定要有插入操作,于是便有了本文.算是对功能实现前的

链表的插入操作总结

链表是一种经常使用的数据结构,有单链表, 双向链表及其循环链表之分. 插入操作是链表的基本操作之中的一个.但大部分人在初学时,多少会感到有些迷惑. 以下时本人的一些小经验. 1 后向插入和前向插入 如果当前节点为P. 后向插入是指在p节点后插入新节点. 前向插入是指在p节点后插入新节点. 对于单链表而言,仅仅有后向插入. 2 基本规律 1) 先保存原链表结构不变,即先改动新节点的前后指针,然后再先远后近. 2) 先远后近是指先改动离p节点远的指针,在改动离它近的指针. 3 链表操作示意图 下图是

单链表的插入操作的实现(0952)SUWST-OJ

Description 建立长度为n的单链表,在第i个结点之前插入数据元素data. Input 第一行为自然数n,表示链式线性表的长度:第二行为n个自然数表示链式线性表各元素值:第三行为指定插入的位置i:第四行为待插入数据元素data. Output 指定插入位置合法时候,输出插入元素后的链式线性表的所有元素,元素之间用一个空格隔开.输入不合法,输出“error!”. Sample Input 5 1 2 3 4 5 3 6 Sample output 1 2 6 3 4 5 代码: #inc

单链表的插入操作

从C和指针这本书中学到的优化插入函数写法: #include<stdio.h> typedef struct Node{ int value; struct Node*link; }Node; int sll_insert(Node **linkp,int new_value){ Node *current=*linkp; while(current!=NULL&&current->value<new_value) { linkp=¤t->link; curr

链表_有序链表(插入删除遍历)

插入的节点位置有两种情况,一是有previous节点,而是没有previous节点 //链结点 public class Link { public long dData; public Link next; public Link(long dd) { dData=dd; } public void displayLink() { System.out.print(dData+" "); } } public class SortedList { private Link first

有序链表的操作

快要上机考试了,所以最近想多总结些,其实这些也很简单,但是平时没怎么学,只是现在才想起突击,唉... 有序链表,所有操作还是那套(增减删),我觉得我这次主要处理下链表的插入,其他的都好说. 首先要定义链表的结构体,我就不写了,直接上代码. /* 2014/12/18 12:27 星期四 writer : ly */ int init_node(linklist &l){ // 初始化单链表 l = (linklist)malloc(sizeof(node)); l -> next = NUL

单链表插入操作

URL:http://jpkc.onlinesjtu.com/CourseShare/Courses/ResourceModule/PreReading.aspx?courseid=701018&nodid=238&chapterid=238&preid=16 单链表的插入操作 1)已知线性链表head,在p指针所指向的结点后插入一个元素x. 在一个结点后插入数据元素时,操作较为简单,不用查找便可直接插入. 操作过程如下图所示: 相关的语句如下: { s=(slnodetype*)

无锁有序链表的实现

无锁有序链表可以保证元素的唯一性,使其可用于哈希表的桶,甚至直接作为一个效率不那么高的map.普通链表的无锁实现相对简单点,因为插入元素可以在表头插,而有序链表的插入则是任意位置. 本文主要基于论文High Performance Dynamic Lock-Free Hash Tables实现. 主要问题 链表的主要操作包含insert和remove,先简单实现一个版本,就会看到问题所在,以下代码只用作示例: struct node_t { key_t key; value_t val; nod

数据结构Java实现03----单向链表的插入和删除

数据结构Java实现03----单向链表的插入和删除 文本主要内容: 链表结构 单链表代码实现 单链表的效率分析 一.链表结构:            概念: 链式存储结构是基于指针实现的.我们把一个数据元素和一个指针称为结点.   数据域:存数数据元素信息的域. 指针域:存储直接后继位置的域. 链式存储结构是用指针把相互直接关联的结点(即直接前驱结点或直接后继结点)链接起来.链式存储结构的线性表称为链表. 链表类型: 根据链表的构造方式的不同可以分为: 单向链表 单向循环链表 双向循环链表 二