单链表
来源:互联网 发布:怎么开淘宝 编辑:程序博客网 时间:2024/06/18 12:07
既然说链表是重中之重,好吧,学习单链表
基本的操作有创建、查找、插入、删除、等等
面试时通常是:创建一个链表(单链表/双向链表),并写出基于该链表的查找、插入、删除算法代码。我的个神
先说说线性表:
说到链表,不得不提线性表,通常线性表是顺序存储结构。线性表的特点是两个数据元素在逻辑上是相邻的,在物理存储上也是相邻的。
这就是线性表
通常说的先进先出的队列,先进后出的栈都是线性表的数据结构。
线性表算法简单实现起来也方便快捷,但是,它的存储特点决定了它的局限性。
尤其是:(1)在作插入删除操作时,要移动大量内存数据。
(2)线性表的总长度一旦确定就不能改变了,除非重新分配内存。比如用realloc
为了克服这些不足,就出现了非顺序存储结构的链表。
重要的是:链表可以方便的实现 前面提到的 队列 的先进先出 栈的 后进先出操作
线性结构和非线性结构很好理解。
线性结构如线性表、链表
网上通俗的解释是:
线性表 就是ABC这样一个个数据按顺序下去的。他们的内存储存也是ABC这样一个个下去的,|A|B|C|...|。就是内存中要连续储存线性链表 就是数据看上去是ABC这样下去的,内存里面是|B|...|C|...|A|...|这样的混乱顺序排列的,就是内存中储存位置任意。他们用节点指针连接。也就是说A数据后面还有个指针指向B数据的内存地址。链表 顾名思义包括线性链表,还有什么循环链表,双向链表啊啥的。。给你画个图把..链表的。(线性链表)(A,B,C,D,E)储存地址 数据 指向地址1 B 99 18 E NULL28 D 1850 A 199 C 28这样的话他们储存在1.18。28.50.99.位置上,而且顺序乱来,但显示出来却是(A,B,C,D,E)
非线性结构如树、图等
好了,言归正传!
所谓单链表是指:数据节点是单向排列的,一个单链表节点,其结构分为两部分,1)数据域:用于存储数据元素的值。2)指针域(链域):用于存储下一个结点的地址,或者说指向其直接后继结点的指针。
一般声明3个指针来操作链表(不限于三个)可以更改,视具体情况而定
Head:用来指向指针的头部,头指针。
p1:用来指向新结点,用来遍历链表的每一个结点
p2:用来指向当前结点。
程序示例:
//创建一个n个元素的单链表#include <stdio.h>#include <malloc.h>//其实也可以写#include <stdlib.h>,因为#include <stdlib.h>中包含了#include <malloc.h>#include <conio.h>typedef struct node{int num;struct node *next;}student;student *create(int n){student *head,*p1,*p2;//已经解释过,head表示指针头,p1表示指向下一个结点,p2表示指向当前结点head = p1 = p2 = NULL;for (int i = 0;i < n; i++){p1 = (student*)malloc(sizeof(student));p1->num = i;if (i == 0){head = p1;}else{p2->next = p1;}p2 = p1;}p2->next = NULL;return p2;}int main(){student *link;for (int i = 1; i <= 5; i++){link = create(i);printf("%d ",link->num);}printf("\n");getch();return 0;}结果如下:
断网了,下次继续~~~
单链表的查找算法
链表的查找算法思路是:
因为要对链表进行查找,而单链表比较蠢,所以只能从最开始的头指针开始
这就需要两个条件
1)单链表的头指针
2)要查询的数值
比如定义的单链表结构体如下:
typedef struct node{int num;struct node *next;}student;那么查找单链表子函数可以写成
//链表按值查找 void find(student *head, int date) { student *p; int n=1; p = head; while(NULL != p && date != p->num) { p = p->next; n++; } if(NULL == p) {//printf("链表中只有一个值%d\n",head->num);printf("链表中没有找到该值"); }else if(date == p->num) { printf("要查找的值%d在链表中第%d个位置\r\n", date, n); } return; }这是按值查找,按值查找就是以要查询的值为中心,从头指针开始,顺序搜索。直到找到正确的值。
具体实现如下:
#include <stdio.h>#include <malloc.h>//其实也可以写#include <stdlib.h>,因为#include <stdlib.h>中包含了#include <malloc.h>#include <conio.h>typedef struct node{int num;struct node *next;}student;student *create(int n){student *head,*p1,*p2;//已经解释过,head表示指针头,p1表示指向下一个结点,p2表示指向当前结点head = p1 = p2 = NULL;for (int i = 0;i < n; i++){p1 = (student*)malloc(sizeof(student));p1->num = i;if (i == 0){head = p1;}else{p2->next = p1;}p2 = p1;}p2->next = NULL;return head;}//链表按值查找 void find(student *head, int date) { student *p; int n=1; p = head; while(NULL != p && date != p->num) { p = p->next; n++; } if(NULL == p) {//printf("链表中只有一个值%d\n",head->num);printf("链表中没有找到该值"); }else if(date == p->num) { printf("要查找的值%d在链表中第%d个位置\r\n", date, n); } return; } int main(){student *f;f = create(10);find(f,1);getch();return 0;}结果如下:
也可以按序号查找,就是从第一个序号(或者称位置遍历),直到找到正确的值
#include <stdio.h>#include <malloc.h>//其实也可以写#include <stdlib.h>,因为#include <stdlib.h>中包含了#include <malloc.h>#include <conio.h>typedef struct node{int num;struct node *next;}student;student *create(int n){student *head,*p1,*p2;//已经解释过,head表示指针头,p1表示指向下一个结点,p2表示指向当前结点head = p1 = p2 = NULL;for (int i = 0;i < n; i++){p1 = (student*)malloc(sizeof(student));p1->num = i;if (i == 0){head = p1;}else{p2->next = p1;}p2 = p1;}p2->next = NULL;return head;}//按序号查找 void research_Number(student *head, int Num) { student *p=head; int i = 1; while(NULL != p && i < Num) { p = p->next; i++; } if(p == NULL) { printf("查找位置不合法\r\n"); }else if(i == 1) { printf("查找位置为头结点且为%d\r\n",p->num); }else if(i == Num) { printf("第%d个位置数据为%d\r\n", i, p->num); } } int main(){student *f;f = create(10);research_Number(f,1);research_Number(f,2);research_Number(f,3);getch();return 0;}
到此,查找告一段落了
删除
删除似乎麻烦一点
删除单链表算法的思路:
先声明两个指针,p1,p2
p1用来遍历链表,查找符合条件的结点。
p2用来指向当前结点。
具体如下:
#include <stdio.h>#include <malloc.h>//其实也可以写#include <stdlib.h>,因为#include <stdlib.h>中包含了#include <malloc.h>#include <conio.h>#include <iostream>typedef struct node{int num;struct node *next;}student;student *create(int n){student *head,*p1,*p2;//已经解释过,head表示指针头,p1表示指向下一个结点,p2表示指向当前结点head = p1 = p2 = NULL;for (int i = 0;i < n; i++){p1 = (student*)malloc(sizeof(student));p1->num = i;if (i == 0){head = p1;}else{p2->next = p1;}p2 = p1;}p2->next = NULL;return head;}student* del(student *head,int i){bool flag = false;if (head){student *p1,*p2;p1 = head;//关键的一步while (p1->num != i && p1->next != NULL ){p2 = p1;p1 = p1->next;}if (p1->num == i){if (p1 == head){head = p1->next;}else{p2->next = p1->next;}}free(p1);flag = true;}if (!flag){printf("\n %d could not been found",i);}return head;}//单链表测长 int length(student *head) { int n = 0; student *p; p = head; while(p != NULL) { p = p->next; n++; } return n; } //单链表打印 void print(student *head) { node *p; int n; n = length(head); std::cout<<"Now, These "<<n<<" records are: "<<std::endl; p = head; if(p != NULL) { while(p != NULL) { std::cout<<p->num<<" -> "; p = p->next; } std::cout<<std::endl; } } int main(){student *f;f = create(10);f = del(f,3);print(f);getch();return 0;}
结果为:
最后一个,插入:
插入的思路:同样定义两个指针p1,p2
p1用来遍历链表,查找符合条件的结点,p2用来指向当前结点
首先判断是不是空链表
如果不是空链表,判断要插入的位置
具体如下:
//插入单链表节点node *insert(node *head, int num){node *p1, *p2, *p3;p2 = head;p1 = (node *)malloc(sizeof(node));//先将要插入的节点申请下~p1->data = num;//思路同删除节点操作while(num > p2->data && p2->next != NULL) {p3 = p2;p2 = p2->next;}if(num <= p2->data){if(head == p2){p1->next = p2;head = p1;}else{p3->next = p1;p1->next = p2;}}else {//此处要细心,别忘了可以在尾部插入节点。p2->next = p1;p1->next = NULL;}return head;}
全部插入实现如下:
#include <iostream>#include <stdio.h>#include <string.h>#include <conio.h>typedef struct student{int data;struct student *next;}node;//建立单链表node* create(){node *head,*p,*s;int x, cycle = 1;head = (node *)malloc(sizeof(node));p = head;while(cycle){std::cout<<"please input the data: ";std::cin>>x;std::cout<<std::endl;if(x != 0){s = (node *)malloc(sizeof(node));s->data = x;p->next = s;p = s;}elsecycle = 0;}head = head->next;p->next = NULL;return head;}//单链表测长int length(node *head){int n = 0;node *p;p = head;while(p != NULL){p = p->next;n++;}return n;}//单链表打印void print(node *head){node *p;int n;n = length(head);std::cout<<"Now, These "<<n<<" records are: "<<std::endl;p = head;if(p != NULL){while(p != NULL){std::cout<<p->data<<" -> ";p = p->next;}std::cout<<std::endl;}}//插入结点node* insert(node *head, int num){node *p0,*p1,*p2;p1 = head;p0 = (node *)malloc(sizeof(node));//待插入的结点p0->data= num;while(p0->data > p1->data && p1->next != NULL){p2 = p1;p1 = p1->next;}if(p0->data <= p1->data){if(p1 == head){p0->next = p1;head = p0;}else{p0->next = p1;p2->next = p0;}}else{p1->next = p0;p0->next = NULL;}return head;}int main(int argc, char* argv[]){node *head;head = create();print(head);//删除结点int num;//插入结点std::cin>>num;head = insert(head, num);print(head);getch();return 0;}结果:
到这里 插入也结束了
单链表是链表的基础,今后还要花时间多学习,先这样吧,更多细节请看这里,这里,这里
当然 中间排序什么的也很重要
如:
#include<iostream>using namespace std;typedef struct student{int data;struct student *next;}node;//创建单链表node *create(){node *head, *p, *s;int x;head = (node *)malloc(sizeof(node));//先创建一个头节点,便于头指针的操作。p = head;printf("Input the data, end with 0 : ");while(1){if(scanf("%d", &x) != EOF && x != 0){//如果输入数据合法,则再创建一个节点;否则跳出循环。s = (node *)malloc(sizeof(node));s->data = x;p->next = s;p = s;}else break;}head = head->next;p->next = NULL;return head;}//计算单链表长度int length(node *head){int n = 0;while(head != NULL){head = head->next;n++;}return n;}//打印单链表void print(node *head){int n = length(head);printf("Output the list %d records : ", n);while(head != NULL){printf(head->next == NULL ? "%d\n" : "%d->", head->data);head = head->next;}}//删除单链表节点node *del(node *head, int num){node *p1, *p2;if(head == NULL) return NULL;p1 = head;while(num != p1->data && p1->next != NULL){//若当前指针所存储的值与要删除的值不符,则向后遍历,直至相等或至最后一个节点。p2 = p1;p1 = p1->next;}if(num == p1->data){//如果链表中存在要删除的节点,则分两种情况:在头节点处或链表中。if(head == p1) head = p1->next;else p2->next = p1->next;free(p1);//别忘了释放删除的节点哦~节约点~}else printf("There is no '%d' \n", num);//找不到要删除的值。return head;}//插入单链表节点node *insert(node *head, int num){node *p1, *p2, *p3;p2 = head;p1 = (node *)malloc(sizeof(node));//先将要插入的节点申请下~p1->data = num;//思路同删除节点操作while(num > p2->data && p2->next != NULL) {p3 = p2;p2 = p2->next;}if(num <= p2->data){if(head == p2){p1->next = p2;head = p1;}else{p3->next = p1;p1->next = p2;}}else {//此处要细心,别忘了可以在尾部插入节点。p2->next = p1;p1->next = NULL;}return head;}//单链表排序node *sort(node *head){node *p;p = head;int n, temp;n = length(head);//运用冒泡排序似乎对链表排序来说是最方便的~(递增)for(int j = 1; j < n; j++){p = head;for(int i = 0; i < n - j; i++){if(p->data > p->next->data){temp = p->data;p->data = p->next->data;p->next->data = temp;}p = p->next;}}printf("\nAfter sorting :\n");return head;}//单链表逆置node *reverse(node *head){node *p1, *p2, *p3;p1 = head;p2 = p1->next;if(head == NULL || head->next == NULL) return head;//逆置的思想:选出三个节点(第三个可能是NULL),操作前两个节点,使其逆置,而后按同样做法操作第二、三个节点和第四个节点~while(p2 != NULL){p3 = p2->next;p2->next = p1;p1 = p2;p2 = p3;}head->next = NULL;head = p1;printf("\nAfter reversing :\n");return head;}int main(){node *head;//创建单链表head = create();print(head);//排序head = sort(head);print(head);//删除单链表int numD;printf("\nInput the value you want to delete : ");scanf("%d", &numD);head = del(head, numD);print(head);//插入单链表int numS;printf("\nInput the value you want to insert : ");scanf("%d", &numS);head = insert(head, numS);print(head);//逆置head = reverse(head);print(head);system("pause");return 0;}
结果显示:
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 单链表
- 美化多系统启动选择菜单burg:在deepin 2013&& ubuntu14.04 上安装测试过,完全可用。
- spring初学一(DI)
- php 获取Ip
- HTTPS与SSL
- 金错刀:当王石遇上互联网思维
- 单链表
- Java内存管理机制
- 关于如何参数OPTIMIZER_INDEX_COST_ADJ和参数OPTIMIZER_INDEX_CACHING
- 判断两条线段是否相交
- java Annotation Meta-annotations
- 水呀水~个人赛C题1113
- nyoj 23 取石子(一)
- iOS控件的Sent Events的含义
- 周记-集训结束了