链表(C和Java代码实现)

C代码实现

一、 逆序输出

题目:逆序输出,当输入-1时表示输入结束。

1. 使用不带头结点的头插入法创建链表实现

每创建一个结点,都使该结点成为头结点,这样头结点不断地向前移动,就可以创建一个没有特定头结点的链表。首先创建的结点,会出现在整个链表的最末端,所以数据的写入是逆序的
【注意:开始的时候,head要初始化为NULL】

#include<stdio.h>
#include<stdlib.h>
struct list_node
{
    int data;
    struct list_node *next;

};
int main()
{
    struct list_node *head,*p,*b,*s,*t;
    int n;
    head=NULL;
    while(1)
    {
        scanf("%d",&n);
        if(n==-1)
            break;
        p=(struct list_node *)malloc(sizeof(struct list_node));
        p->data=n;
        p->next=head;
        head=p;
    }
    t=head;

    while(t!=NULL)
    {
        printf("%d ",t->data);
        t=t->next;
    }
    return 0;
}

开始时候,head 是一个空指针,创建一个结点p。现在head是指向一个链表的头结点,创建了一个新的结点p,向前插入。所以要p->next = head;然后再使head成为新链表的头结点。

2. 创建双向链表实现
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct DOUBLE_LIST
{
    int data;
    struct DOUBLE_LIST *prev;
    struct DOUBLE_LIST *next;
}double_list;

double_list *createlist()       //创建有n个元素的双向链表 并输入元素
{
    double_list *head, *p, *q;
    int n,x;
    head = (double_list *)malloc(sizeof(double_list));
    head->prev = head;
    head->next = head;
    p = head;

    while(1){
        scanf("%d", &x);
        if(x==-1)
            break;
        q = (double_list *)malloc(sizeof(double_list));
        q->data = x;
        p->next = q;
        head->prev = q;
        q->prev = p;
        q->next = head;
        p = q;
    }
    return head;
}
//遍历并且输出这些元素
void printlist(double_list *head)
{
    double_list *p;
    p = head;
    p = p->prev;
    while(p!=head)
    {
        printf("%d ", p->data);
        p = p->prev;
    }
    //printf("\n");
}
int main()
{
    double_list *head;
    head = createlist();
    printlist(head);
    return 0;
}

C语言数据结构-创建链表的四种方法

二、 删除单链表的第i个元素

/*
title : demo solution to problem 1387
author : John
date : 2014.1.9
last modify : 2014.1.9
*/

#include <stdio.h>
#include <stdlib.h>

// 定义链表数据类型
typedef struct LinkList{
    int value;
    struct LinkList *next;
}LL;

LL *mylinklist;  // 单链表
int lcount;      // 单链表元素个数

int N;   // 单链表共有n个节点
int I;   // 要删的元素的位置


// 从左到右输出链表元素
void printlist()
{
    LL *p = mylinklist;

    while( p )
    {
        printf( "%d ", p->value );
        p = p->next;
    }
    //printf( "\n" );
}


// 读数据,建链表
int readin()
{
    int va;   // 读入的元素值
    LL *tt;   // 临时节点
    LL *last; // 链尾指针

    scanf( "%d%d", &N, &I );
    lcount = N;

    for( int kk=0 ; kk < N; kk++ )
    {
        scanf( "%d", &va );

        tt = (LL *)malloc( sizeof(LL) );
        if( !tt )   // 申请节点空间失败
            return -1;

        tt->value = va;
        tt->next = NULL;
        if( kk == 0 ) // 链首节点,特殊处理
        {
            mylinklist = tt;
            last = tt;
        }
        else             // 其他节点
        {
            last->next = tt;
            last = tt;
        }
    }
    return 0;
}

// 删除单链表L上的第i个数据节点
int Del_LinkList( int i )
{
    if( i < 1 || i > lcount ) // 删除的位置有误
    {
        printf( "nothing to do" );
        return 0;
    }

    if( i == 1 )        // 删除链头
    {
        LL *s = mylinklist;      // 链首节点
        mylinklist = mylinklist->next;
        free(s);        // 释放*s
        lcount --;
        printlist();
        return 0;
    }

    LL *p = mylinklist;
    int cc = 1;
    while( p && cc < i-1 )  // 定位第i-1个节点
    {
        cc ++;
        p = p->next;
    }

    LL *s = p->next;        // s指向第i个节点
    p->next = s->next;    // 从链表中删除
    free(s);            // 释放*s
    lcount --;
    printlist();

    return 0;
}

int main()
{
    if( !readin() )
    {
        Del_LinkList( I );
    }

    return 0;
}

Java代码实现

一、单向链表(插入、删除、遍历、反转、合并两个有序链表)

1. 定义结点类

public class Node {
	
	int data;
	Node next; //指向下一个节点
	
	public Node(int data) {
		this.data = data;
	}	
	
}

2. 实现单链表的建立、插入、遍历以及删除,还有链表反转,合并两个有序链表等操作

//实现链表的建立、插入、遍历以及删除
public class SingleLinkedList {
	
	//头结点(不是首元结点,注意两者区别)
	private Node head = new Node(-1);
	
	public Node getHead() {
		return this.head;
	}
	
	public void setHead(Node head) {
		this.head = head;
	}
	
	//将每个节点添加到链表的最后一个节点
	public void buildByLast(Node node) {
		Node temp = head;
		while (temp.next != null) {
			temp = temp.next;
		}
		temp.next = node;
	}
	
	
	//将每个节点按顺序插入到链表中
	public void buildByOrder(Node node) {
		Node temp = head;
		boolean flag = false; //判断是否已插入
		while (temp.next != null) {
			if (temp.next.data > node.data) { //找到位置,插入节点
				node.next = temp.next;
				temp.next = node;
				flag = true;
				break;
			}
			temp = temp.next;
		}
		if (!flag) { //还没插入,就把node结点插到最后一个
			temp.next = node;
		}
	}
	
	//删除结点
	public void deleteNode(int n) {
		if (head.next == null) {
			System.out.println("列表为空");
			return;
		}
		Node temp = head;
		boolean flag = false; //判断是否已删除
		while (temp.next != null) {
			if (temp.next.data == n) {
				temp.next = temp.next.next;
				flag = true;
				break;
			}
			temp = temp.next;
		}
		if (!flag) {
			System.out.println("没有找到该结点");
		}
	}
	
	//遍历每个结点
	public void getAll() {
		Node temp = head.next;
		while (temp != null) {
			System.out.print(temp.data + " ");
			temp = temp.next;
		}
		System.out.println();
	}
	
	//单链表反转   写法1
	//(头结点插入法:把每一个结点从原来位置删除,然后插入到头结点后面,最终完成反转)
	public void reverseNode1() {
		/*链表为空或只有一个元素则直接返回*/
		if (head.next == null || head.next.next == null) {
			return;
		}
		Node temp1 = head.next; 
		Node temp2 = null;
		Node temp3 = temp1; //temp3为头结点的下一个结点
		while (temp1.next != null) {
			temp2 = temp1.next;
			//删掉temp2结点
			temp1.next = temp1.next.next;
			//把temp2结点插入到头结点后面
			temp2.next = temp3;
			head.next = temp2;
			//使temp3重新成为头结点的下一个结点
			temp3 = temp2;
		}
	}
	
	//单链表反转  写法2
	//原地反转法
	public void reverseNode2() {
		 /*链表为空或只有一个元素则直接返回*/
		if (head.next == null || head.next.next == null) {
			return;
		}
		Node t = null;
		Node p = head.next ;
		Node q = head.next.next;
		while (q != null) {
			t = q.next;
			q.next = p;
			p = q;
			q = t;
		}
		/*此时q指向原始链表最后一个元素,也是逆转后的链表的表头元素*/  
		head.next.next = null; /*设置链表尾*/  
		head.next = p; /*调整链表头*/  
	}	
	
	//两个有序单链表的合并(单链表包含头结点)
	public static Node combine(Node head1, Node head2) {
		Node t1 = head1.next;
		Node t2 = head2.next;
		Node headNode = new Node(-1);
		Node finalHead = headNode;
		
		while (t1 != null && t2 != null) {
			if (t1.data < t2.data) {
				headNode.next = t1;
				t1 = t1.next; 
			} else {
				headNode.next = t2;
				t2 = t2.next;
			}
			headNode = headNode.next;
		}
		if (t1 == null) {
			headNode.next = t2;
		} else if (t2 == null){
			headNode.next = t1;
		}
		return finalHead;	
	}
}

3. 测试

测试插入、遍历、反转、删除操作

import java.util.Scanner;

public class TestSingleLinkedList {
	
	public static void main(String[] args) {
		
		SingleLinkedList linkList = new SingleLinkedList();
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt(); 
		for (int i = 0; i < n; i++) {
			//linkList.buildByLast(new Node(sc.nextInt())); //直接插最后
			linkList.buildByOrder(new Node(sc.nextInt())); //按大小插入
		}
		
		linkList.getAll(); //遍历输出
		linkList.reverseNode1(); //反转
		linkList.getAll();  //遍历输出
		linkList.reverseNode2(); //反转
		linkList.getAll(); //遍历输出 
		
		while (true) {
			linkList.deleteNode(sc.nextInt()); //删除结点
			linkList.getAll(); //遍历输出 
		}
	}
}

测试合并两个有序链表

import java.util.Scanner;

public class TestSingleLinkedList {
	
	public static void main(String[] args) {
		
		SingleLinkedList linkList1 = new SingleLinkedList();
		SingleLinkedList linkList2 = new SingleLinkedList();
		
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt();
		for (int i = 0; i < n; i++) {
			linkList1.buildByOrder(new Node(sc.nextInt())); //按大小插入
		}
		
		int n1 = sc.nextInt();
		for (int i = 0; i < n1; i++) {
			linkList2.buildByOrder(new Node(sc.nextInt())); //按大小插入
		}
		
		
		linkList1.getAll(); //遍历输出	
		linkList2.getAll();  //遍历输出
		
		//合并两个有序链表
		Node head = SingleLinkedList.combine(linkList1.getHead(),  linkList2.getHead());
		
		//结果输出
		SingleLinkedList l1 = new SingleLinkedList();
		l1.setHead(head); 
		l1.getAll(); //合并后的链表遍历输出
					
	}

}

二、双向链表(插入、删除、遍历)

1. 定义结点类

class Node1 {
	int data;
	Node1 next; //指向下一个节点
	Node1 pre; //指向上一个节点
	
	public Node1(int data) {
		this.data = data;
	}
}

2. 实现双向链表的创建、插入、遍历以及删除

public class DoublyLinkedList {
	
	//头结点
	private Node1 head = new Node1(-1);
	
	//将每个节点添加到链表的最后一个节点
	void buildByLast(Node1 node) {
		Node1 temp = head;
		while(temp.next != null) {
			temp = temp.next;
		}
		//当前节点的pre指向前面的链表
		node.pre = temp;
		//最后一个节点的next指向node
		temp.next = node;
	}

	//删除节点
	public void deleteNode(int n) {
		if (head.next == null) {
			System.out.println("列表为空");
			return;
		}
		boolean flag = false;//标记是否已删除
		Node1 temp = head.next;
		while(temp != null) {
			if (temp.data == n) {
				temp.pre.next = temp.next;
				flag = true;
				break;
			}
			temp = temp.next;
		}
		if (!flag) {
			System.out.println("没有找到该节点");
			return;
		}
		if (temp.next != null) {
			temp.next.pre = temp.pre;
		}
		
	}
	 
	//遍历每个节点
	public void getAll() {
		Node1 temp = head.next;
		while(temp != null) {
			System.out.print(temp.data + " ");
			temp = temp.next;
		}
		System.out.println();
	}
}

3. 测试

import java.util.Scanner;

public class TestDoublyLinkedList {
	
	public static void main(String[] args) {
		
		DoublyLinkedList linkList = new DoublyLinkedList();
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt();
		for (int i = 0; i < n; i++) {
			linkList.buildByLast(new Node1(sc.nextInt())); //直接插最后
			
		}
		
		linkList.getAll(); //遍历输出
		
		while (true) {
			linkList.deleteNode(sc.nextInt()); //删除结点
			linkList.getAll(); //遍历输出 
		}
	}
}

三、循环链表解决约瑟夫问题

1.创建环形链表解决约瑟夫问题:

public class CircleLinkedList {

	private Node first = null; //设置为环形链表的第一个节点,即首元结点
	
	//创建环形链表
	public void build(int nums) {
		//定义当前节点
		Node cur = null;
		for(int i=1; i <= nums; i++) {
			Node circleLink = new Node(i);
			if (i==1) { //只有一个节点时,next指向自己
				first = circleLink;
				circleLink.next = first;
			} else {
				cur.next = circleLink;
				circleLink.next = first;
			}
			cur = circleLink;
		}
	}
	
	//约瑟夫问题删除第k个节点
	public void deleteNode(int k) {
		
		Node cur = first; //当前节点
		Node q = first; //当前节点的前一个节点
		//找到首元节点的前一个节点
		while (q.next != first) {
			q = q.next;
		}

		int i = 1; //定义初始位置
		while(true) {
			if (q == cur) { //只剩一个节点
				System.out.println("最终剩余节点:" + cur.data);
				break;
			}
			if (i == k) { //找到要删除的节点位置
				System.out.println("删除节点:" + cur.data);
				q.next = cur.next;
				cur = cur.next;
				i=1; //初始位置重新定为1
				continue;
			}
			i++;
			cur = cur.next;
			q = q.next;
		}
		first = cur;
		cur.next = first;
	}
	
	//遍历环形链表
	public void getAll() {
		Node w = first;
		while (w.next != first) {
			System.out.print(w.data + " ");
			w = w.next;
		}
		System.out.println(w.data);
	}
}

2. 测试:

import java.util.Scanner;
import java.util.Timer;

public class TestCircileLinkedList {
	public static void main(String[] args) {
		CircleLinkedList cirLinkList = new CircleLinkedList();
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt(); //输入n个节点
		int m = sc.nextInt(); //删除约瑟夫循环的第m个位置
		for (int i = 1; i <= n; i++) {
			cirLinkList.build(i);
		}
		cirLinkList.getAll();
		cirLinkList.deleteNode(m);	
		cirLinkList.getAll();
	}
}

/**
7 2
1 2 3 4 5 6 7
删除节点:2
删除节点:4
删除节点:6
删除节点:1
删除节点:5
删除节点:3
最终剩余节点:7
7
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值