• 单链表操作 C实现


    struct LNode { //定义一个节点

            int data; //数据域

            struct LNode *next; //指针域

    };

    0.初始化

    1. typedef sturct LNode{ //定义单链表结点类型
    2. int data ; //每个结点存放一个数据元素
    3. struct LNode *next; //指针指向下一个结点
    4. }LNodes, *LinkList;
    5. typedef LNode{ //定义单链表结点类型
    6. int data ; //每个结点存放一个数据元素
    7. struct LNode *next; //指针指向下一个结点
    8. };
    9. //typedef struct LNode LNodes;
    10. //typedef struct LNOde *LinkList;
    11. //上面俩个是等价的
    12. 1)不带头结点的单链表
    13. bool InitList(LinkList &L) //初始化空链表
    14. {
    15. L = NULL; //空表没有任何结点
    16. return true;
    17. }
    18. void test()
    19. {
    20. LinkList L ; //声明一个指向单链表的指针
    21. //初始化一个空表
    22. InitList (L);
    23. }
    24. 判断是否为空
    25. bool Empty(LinkList L){
    26. if(L == NULL)
    27. return true;
    28. else
    29. return false;
    30. }
    31. //或:
    32. bool Empty(LinkList L){
    33. return (L == NULL);
    34. }
    35. 2)带头节的单链表
    36. //初始化一个单链表(带头结点)
    37. bool InitList (LinkList &L){
    38. L = (LNode * ) malloc (sizeof(LNode)); //分配一个头结点
    39. if (L == NULL) //内存不足分配失败
    40. return false;
    41. L->next = NULL;
    42. return true;
    43. }
    44. 判断是否为空
    45. bool Empty(LinkList L){
    46. if(L->next == NULL)
    47. return true;
    48. else
    49. return false;
    50. }

    1.尾插法建立链表

    1. struct LNode *CreateLinkList1(void){ //尾插法创建链表
    2. struct LNode *head=(struct LNode *)malloc(LEN); //创建一个头节点
    3. head->next=NULL; //开始时头节点指针指向NULL
    4. struct LNode *h=head,*s;
    5. struct LNode info;//接收从键盘输入每个节点的数据
    6. scanf("%d",&info.data);
    7. while(info.data!=0){ //创建链表,直到输入数据为0结束
    8. s=(struct LNode *)malloc(LEN);
    9. s->data=info.data; //节点s接收输入数据
    10. h->next=s; //尾插如链表尾部
    11. h=h->next; //保持h位于链表末尾,方便接收下一个节点数据
    12. scanf("%d",&info.data);
    13. }
    14. h->next=NULL; //链表末尾指向NULL
    15. return head;
    16. }
    1. typedef struct LNode {
    2.        int data; //数据域
    3.        struct LNode *next; //指针域
    4.   }LNodes,*LinkList;
    5. LNodes *insertBack(LNodes *head, LNodes *tail, LNodes *newNode)
    6. {
    7. //tail = head;
    8. newNode->next = NULL;
    9. tail->next = newNode;
    10. tail = newNode;
    11. return head;
    12. }
    13. LNodes *insertBacks(LNodes *head, LNodes *newNode)
    14. {
    15. LNodes *tail;
    16. LNodes *h = head;
    17. while(h && h->next)
    18. h = h->next;
    19. tail = h;
    20. newNode->next = NULL;
    21. tail->next = newNode;
    22. tail = newNode;
    23. return head;
    24. }

    2.头插法建立链表

    1. struct LNode *CreateLinkList2(void){ //头插法创建链表
    2. struct LNode *head=(struct LNode *)malloc(LEN);
    3. head->next=NULL;
    4. struct LNode *h=head,*s;
    5. struct LNode info;
    6. scanf("%d",&info.data);
    7. while(info.data!=0){ //创建链表,直到输入数据为0结束
    8. s=(struct LNode *)malloc(LEN);
    9. s->data=info.data;//节点s接收输入数据
    10. s->next=h->next; //头插插入头节点尾部,插入节点要始终跟着头节点后面
    11. h->next=s;
    12. scanf("%d",&info.data);
    13. }
    14. return head;
    15. }
    1. typedef struct LNode {
    2.        int data; //数据域
    3.        struct LNode *next; //指针域
    4.   }LNodes,*LinkList;
    5. LNodes *insertFront(LNodes *head, LNodes *newNode)
    6. {
    7. newNode->next = head->next;
    8. head->next = newNode;
    9. return head;
    10. }

    3.链表结点删除操作

    1. struct LNode *Delete(struct LNode *head,int x){ //删除链表中值为x的节点
    2. struct LNode *p=head->next,*pre=head,*q;
    3. while(p!=NULL){
    4. if(p->data==x){
    5. q=p;
    6. pre->next=p->next;
    7. p=p->next;
    8. free(q);
    9. }
    10. else{
    11. pre=p;
    12. p=p->next;
    13. }
    14. }
    15. return head;
    16. }

    4.在有序链表中插入一个结点

    1. struct LNode *Insert(struct LNode *head,int x){ //创建一个递增链表,将x插入链表,并保持有序
    2. struct LNode *p=head->next,*pre=head,*q;
    3. while(p!=NULL){
    4. if(x<p->data){
    5. q=(struct LNode *)malloc(LEN); //为插入值分配一个节点空间
    6. q->data=x;
    7. pre->next=q;
    8. q->next=p;
    9. break;
    10. }
    11. else{
    12. pre=p;
    13. p=p->next;
    14. }
    15. }
    16. return head;
    17. }

    5.遍历

    1. void print(struct LNode *head){ //遍历链表并输出各个节点的数据
    2. struct LNode *p=head->next;
    3. while(p!=NULL){
    4. printf("%d->",p->data);
    5. p=p->next;
    6. }
    7. printf("NULL\n");
    8. }

    运行程序结果:

    1. 尾插法:1 2 3 4 6 7 8 9 0
    2. 1->2->3->4->6->7->8->9->NULL
    3. 头插法:1 2 3 4 6 7 8 9 0
    4. 9->8->7->6->4->3->2->1->NULL
    5. 删除节点81->2->3->4->6->7->9->NULL
    6. 插入节点51->2->3->4->5->6->7->9->NULL
    7. Press any key to continue...

    完整的代码如下:

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #define LEN sizeof(struct LNode) //LEN表示一个节点大小
    4. struct LNode{ //定义一个节点
    5. int data; //数据域
    6. struct LNode *next; //指针域
    7. };
    8. struct LNode *CreateLinkList1(void){ //尾插法创建链表
    9. struct LNode *head=(struct LNode *)malloc(LEN); //创建一个头节点
    10. head->next=NULL; //开始时头节点指针指向NULL
    11. struct LNode *h=head,*s;
    12. struct LNode info;//接收从键盘输入每个节点的数据
    13. scanf("%d",&info.data);
    14. while(info.data!=0){ //创建链表,直到输入数据为0结束
    15. s=(struct LNode *)malloc(LEN);
    16. s->data=info.data; //节点s接收输入数据
    17. h->next=s; //尾插如链表尾部
    18. h=h->next; //保持h位于链表末尾,方便接收下一个节点数据
    19. scanf("%d",&info.data);
    20. }
    21. h->next=NULL; //链表末尾指向NULL
    22. return head;
    23. }
    24. struct LNode *CreateLinkList2(void){ //头插法创建链表
    25. struct LNode *head=(struct LNode *)malloc(LEN);
    26. head->next=NULL;
    27. struct LNode *h=head,*s;
    28. struct LNode info;
    29. scanf("%d",&info.data);
    30. while(info.data!=0){ //创建链表,直到输入数据为0结束
    31. s=(struct LNode *)malloc(LEN);
    32. s->data=info.data;//节点s接收输入数据
    33. s->next=h->next; //头插插入头节点尾部,插入节点要始终跟着头节点后面
    34. h->next=s;
    35. scanf("%d",&info.data);
    36. }
    37. return head;
    38. }
    39. struct LNode *Delete(struct LNode *head,int x){ //删除链表中值为x的节点
    40. struct LNode *p=head->next,*pre=head,*q;
    41. while(p!=NULL){
    42. if(p->data==x){
    43. q=p;
    44. pre->next=p->next;
    45. p=p->next;
    46. free(q);
    47. }
    48. else{
    49. pre=p;
    50. p=p->next;
    51. }
    52. }
    53. return head;
    54. }
    55. struct LNode *Insert(struct LNode *head,int x){ //创建一个递增链表,将x插入链表,并保持有序
    56. struct LNode *p=head->next,*pre=head,*q;
    57. while(p!=NULL){
    58. if(x<p->data){
    59. q=(struct LNode *)malloc(LEN); //为插入值分配一个节点空间
    60. q->data=x;
    61. pre->next=q;
    62. q->next=p;
    63. break;
    64. }
    65. else{
    66. pre=p;
    67. p=p->next;
    68. }
    69. }
    70. return head;
    71. }
    72. void print(struct LNode *head){ //遍历链表并输出各个节点的数据
    73. struct LNode *p=head->next;
    74. while(p!=NULL){
    75. printf("%d->",p->data);
    76. p=p->next;
    77. }
    78. printf("NULL\n");
    79. }
    80. int main(void){
    81. struct LNode *p1,*p2,*q,*y;
    82. printf("尾插法:");
    83. p1=CreateLinkList1(); //p1接收尾插法传回的头节点
    84. print(p1);
    85. printf("头插法:");
    86. p2=CreateLinkList2(); //p2接收头插法传回的头节点
    87. print(p2);
    88. printf("删除节点8:");
    89. q=Delete(p1,8);
    90. print(p1);
    91. printf("插入节点5:");
    92. y=Insert(p1,5);
    93. print(y);
    94. }

    ---------------------------------------------------------------------------

    1. LinkList revert0(LinkList head) {
    2. if (head == NULL || head->next == NULL)
    3. return head;
    4. LinkList p1,p2,p3;
    5. p1 = head, p2 = head->next;
    6. while(p2){
    7. p3 = p2->next;
    8. p2->next = p1;
    9. p1 = p2;
    10. p2 = p3;
    11. }
    12. head->next = NULL; //important ,if not ,will has circle
    13. head=p1;
    14. return head;
    15. }
    16. LinkList revert1(LinkList head) {
    17. LinkList pRevHead = NULL;
    18. LinkList pPrev = NULL;
    19. LinkList pNodeNext;
    20. LinkList pNode = head;
    21. while (pNode) {
    22. pNodeNext = pNode->next;
    23. if (pNodeNext == NULL)
    24. pRevHead = pNode;
    25. pNode->next = pPrev;
    26. pPrev = pNode;
    27. pNode = pNodeNext;
    28. }
    29. return pRevHead;
    30. }
    31. void DeleteAll(LinkList head){
    32. LinkList p = head;
    33. while (p!= NULL){
    34. LinkList pdel = p;
    35. p = p->next;
    36. free(pdel);
    37. }
    38. }
    39. void PrintList(LinkList head) {
    40. while(head) {
    41. printf("%d ", head->data);
    42. head = head->next;
    43. }
    44. printf("\n");
    45. }
    46. void PrintListReverse(LinkList head){
    47. if (head !=NULL){
    48. PrintListReverse(head->next);
    49. printf("%d ", head->data);
    50. }
    51. if (!head)
    52. printf("\n");
    53. }
    54. void insertL(void) {
    55. LinkList *head = (LinkList)malloc(sizeof(LinkList));
    56. for (int i = 0; i < 10; i++) {
    57. LinkList tmp = (LinkList)malloc(sizeof(LinkList));
    58. tmp->data = i + 1;
    59. tmp->next = NULL;
    60. if (i < 5) {
    61. InsertBack(head, head,tmp);
    62. PrintList(head);
    63. }
    64. else {
    65. InsertFront(head,tmp);
    66. PrintList(head);
    67. }
    68. }
    69. PrintList(head);
    70. PrintListReverse(head);
    71. printf("\n");
    72. LinkList rp = revert0(head);
    73. PrintList(rp);
    74. printf("\n");
    75. LinkList rp1 = revert1(rp);
    76. PrintList(rp1);
    77. DeleteAll(rp1);
    78. }
    79. int main(int argc , char *argv []){
    80. insertL();
    81. }

    头插法和尾插法详解

    头插法
    核心代码:
    head->next = NULL;
    s->next = head->next;
    head->next = s;

    单个结点


    原始状态


    第一个元素插入的过程(注意:1和2的顺序不能颠倒,不然会导致链表缺失)


    第一个元素插入后


    第二个元素插入的过程(其余元素插入的过程也类似)


    第二个元素插入后

    尾插法
    核心代码:
    tail = head;
    s->next = NULL;
    tail->next = s;
    tail = s;

    原始状态


    第一个元素插入的过程(注意:2和3的顺序不能颠倒,不然会导致链表的生成出错)


    第一个元素插入后


    第二个元素插入的过程(其余元素插入的过程也类似)


    第二个元素插入后


    头插法和尾插法的对比
    头插法建立链表的算法简短易懂,但是生成链表的结点顺序与原来输入的顺序相反,而用尾插法建立链表可使输入和生成的结点顺序相同

    为什么会这样呢?
    根据上面的头插法和尾插法的算法,我们很容易知道,当用头插法依次插入值分别为1,2,3,4,5的结点(也叫做元素)后,单链表会如下图所示:


    但是用尾插法同样插入值分别为1,2,3,4,5的结点后,单链表却会如下图所示:

    而在这两个链表中,输出链表中各个元素的值只能从已知的头结点head开始遍历,所以分别用头插法和尾插法创建链表后,依次输出的元素的值刚好是相反的

    验证小例子:

    1. #include <stdio.h>
    2. #include <malloc.h>
    3. typedef struct node
    4. {
    5. struct node* next;
    6. int data;
    7. }LinkList;
    8. //定义LinkList为struct node类型,即struct node可直接用LinkList来表示,方便定义
    9. //头插法创建单链表
    10. int main (void)
    11. {
    12. int i, len = 5;
    13. //len表示链表的长度
    14. LinkList* head, * s;
    15. //head为LinkList*类型的指针变量,表示头指针
    16. head = (LinkList*)malloc (sizeof (LinkList));
    17. //malloc (sizeof (LinkList))意思是让系统分配内存大小为sizeof (LinkList)的空间
    18. head->next = NULL;
    19. //令头指针的所指向结点的指针域为空
    20. for (i = 0; i < len; i++)
    21. {
    22. s = (LinkList*)malloc (sizeof (LinkList));
    23. printf ("请输入该元素的值:");
    24. scanf ("%d", &s->data);
    25. s->next = head->next;
    26. head->next = s;
    27. }
    28. //以下代码是为了将单链表中各个元素的值依次打印出来
    29. LinkList* q;
    30. q = (LinkList*)malloc (sizeof (LinkList));
    31. q = head->next;
    32. while (q != NULL)
    33. {
    34. printf ("%d", q->data);
    35. q = q->next;
    36. }
    37. return 0;
    38. }


    结果:
    请输入该元素的值:1
    请输入该元素的值:2
    请输入该元素的值:3
    请输入该元素的值:4
    请输入该元素的值:5
    54321

    1. #include <stdio.h>
    2. #include <malloc.h>
    3. typedef struct node
    4. {
    5. struct node* next;
    6. int data;
    7. }LinkList;
    8. //尾插法创建单链表
    9. int main (void)
    10. {
    11. int i, len = 5;
    12. LinkList* head,* s,* tail;
    13. //tail表示尾指针
    14. head = (LinkList*)malloc (sizeof (LinkList));
    15. tail = head;
    16. for (i = 0; i < len; i++)
    17. {
    18. s = (LinkList*)malloc (sizeof (LinkList));
    19. printf ("请输入该元素的值:");
    20. scanf ("%d", &s->data);
    21. s->next = NULL;
    22. tail->next = s;
    23. tail = s;
    24. }
    25. //以下代码是将单链表中各个元素的值依次打印出来
    26. LinkList* q;
    27. q = head->next;
    28. while (q != NULL)
    29. {
    30. printf ("%d", q->data);
    31. q = q->next;
    32. }
    33. return 0;
    34. }



    结果:
    请输入该元素的值:1
    请输入该元素的值:2
    请输入该元素的值:3
    请输入该元素的值:4
    请输入该元素的值:5
    12345
    ————————————————
     

  • 相关阅读:
    go监听程序关闭
    使用HHDBCS管理Redis
    安全防御——一、防火墙的基本概念
    微信小程序开发详细步骤是什么?
    在嵌入式里面实现printf()类似的功能
    Redis知识点复习
    【路径规划】基于梯度下降算法求解自定义起点终点障碍路径规划问题附matlab代码
    ElasticSearch学习(三): index的Settings配置参数
    Oracle (7)Online Redo Log Files
    黑苹果修改三码步骤
  • 原文地址:https://blog.csdn.net/phone1126/article/details/133389562